出于为每种可能的条件编写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 。