出于为每种可能的条件编写ifs / elseifs的习惯

在解析xml文档的节点或属性时,如果文档很大,我会有一堆ifs和else语句。

显然,从长远来看,100多个ifs不能构成可维护的代码。

而不是这样做,还有另一种更好的方法吗? 我在Hanselman的博客上读到了他的一个朋友,他的情况相同并编写了大量的ifs / else if和一般代码差。 Hanselman提供了一些更易于维护的片段,但整个代码都不可用,因此有点难以理解究竟是什么(整个图片)正在进行中。 生活在if之后,否则

我正在使用.NET 3.5所以我有完整的扩展方法和LINQ可供我使用。 但是,我使用.NET 2.0作品,所以也会欣赏v2.0中的任何解决方案。 🙂

我的代码看起来与Hanselman网站上的问题非常相似:

if(xmlNode.Attributes [“a”]。Value ==“abc”{

}
else if(xmlNode.Attributes [“b”]。Value ==“xyz”
{
wt = MyEnum.Haze;
}

我可以只有一个字典存储我正在寻找的值作为键,也许是值中的委托(或者我想要在找到所需值时发生的任何事情),所以我可以说if(containskey)获得委托并执行它,在伪代码中。

这种事情一直在继续。 显然非常天真的编码方式。 解析文本文档的值等问题我也有同样的问题。

谢谢

你在这里做的是执行一系列测试。 对于每个测试,如果谓词为true,则执行操作。 测试通过后,停止处理列表。 对?

有几个人建议使用字典,但使用字典的问题是你不能控制字典中的项目顺序。 如果你想按特定的顺序执行测试(正如你所说的那样),那就不行了。 所以列表似乎是要走的路。

假设谓词正在检查XmlElement ,这是一种function性的方法。

您的测试是类的实例:

 class Test { string Predicate { get; set; } Action Verb { get; set; } Test(string predicate, Action verb) { Predicate = predicate; Verb = verb; } bool Execute(XmlElement e) { if (e.SelectSingleNode(Predicate) != null) { Verb(); return true; } return false; } } 

要填充测试列表:

 List tests = new List(); tests.Add(new Test("@foo = 'bar'", Method1)); tests.Add(new Test("@foo = 'baz'", Method2)); tests.Add(new Test("@foo = 'bat'", Method3)); 

要执行测试:

 foreach (Test t in tests) { if (t.Execute()) break; } 

你已经消除了很多if / else杂乱,但是你用它代替了它:

 void Method1() { ... do something here } void Method2() { ... do something else here } 

但是,如果您的方法命名很好,则会产生非常干净的代码。

要使用.NET 2.0,我认为您需要将其添加到代码中:

 public delegate void Action(); 

因为我认为这种类型是在3.0中定义的。 我错了。

如果需要将 >映射到 >,则无法避免在某处定义该映射。 这完全取决于您可以对条件做出多少假设以及您在这些条件下做了多少假设。 我认为字典的想法很好。 为了提供尽可能多的灵活性,我将从这样开始:

 Dictionary, Action> mappings; 

然后开始简化你可以做到的地方。 例如,您是否经常将wt设置为MyEnum的值,如示例中所示? 如果是这样,你想要这样的东西:

 Func setWt = val => () => wt = val; 

对于大概常见的情况,您只需检查属性是否具有特定值,您也需要一些便利:

 Func> checkAttr = (attr, val) => node => node.Attributes[attr] == val; 

现在您的字典可以包含以下项目:

  ... {checkAttr("a", "abc"), setWt(MyEnum.Haze)}, ... 

哪个好看又简洁,但也不仅限于简单的 >到 >映射。 好的,现在你有一个关于这些条件 - 动作对的大词典,你只需说:

 foreach(DictionaryEntry, Action> mapping in mappings) { if (mapping.Key(xmlNode)) { mapping.Value(); break; } } 

如果您避免使用lambda语法和字典初始值设定项,那么您应该可以在2.0中执行此操作。

您所指的链接拼出了我最喜欢的方法之一 – 填充字典并将其用作从xml属性到您正在设置的值的地图等。

我使用的另一个“技巧”是对此进行扩展。 如果包含特定属性的逻辑不仅仅是设置值,那么可以为委托创建属性名称(或值)的字典,其中委托设置您的值并可选地执行某些逻辑。

这很好,因为它适用于.net 2和.net3 / 3.5。 但是,代表可以更好地在.net 3.5中进行设置。

一旦你有了地图,那么你就可以在所有属性上进行foreach循环,只需查找委托,如果它存在,则调用它,如果它没有,则继续/ throw / etc – 全部取决于你。

好吧,我会在3.5中使用LINQ。 但是,您是否考虑过使用类型化数据集; 这是一种可能性还是架构太松散了? 您可以推断出架构并仍然减少了很多gobbeldy-gook代码。 这是一种方法。

根据文档和场景以及使用if / elses的内容…如果是用于validationXML文档,请根据模式对其进行validation。 如果它有效,你可以安全地假设存在某些元素……

告诉你需要做什么有点难。 如果要根据XML属性设置一个变量,那么Hanselman提到的一行方法是最优雅的。

 MyEnum wt = (MyEnum)Enum.Parse(typeof(MyEnum), xmlNode.Attributes["a"].Value, true); 

从您提供的简短示例看来,您可能需要根据不同的XML属性设置变量,如果是这种情况,您可能无法满足对大型if / else块的需求。

如果您在处理的XML中确实具有相似的结构,则有时可以更轻松地将XML节点作为DataRow进行处理。 如果你的XML到处都是,那么这种方法并不是很好。

 DataSet xmlDerivedSet = new DataSet(); xmlDerivedSet.ReadXml(xmlFilename); foreach (DataRow row in xmlDerivedSet.Tables[0].Rows) { MyClass xmlDerivedClass = new MyClass(row); } 

如果您正在为每个大节点进行处理,您可能还希望有一些特定类型的xml读取器类,以便更清晰地集成它与应用程序的实际逻辑。

假设您正在处理的是您在Xml中收到的大量客户数据。 你可以定义一个类,如:

 public class CustomerXmlReader { public class CustomerXmlReader(XmlReader xml){} public Customer Read() { // read the next customer } } 

这样,应用程序的其余部分就可以继续使用Customer对象,并避免将其与Xml处理混合使用。

一旦您清除了实现细节,Scott Hanselman所描述的是一种简单的表驱动方法。 这些在许多书中都有讨论,比如史蒂夫麦康奈尔的“代码完成”,第12章(任一版本)。 这里也讨论了Stack Overflow 。