如果案例不相交,则打开类型

时间:2017-10-26 13:50:34

标签: c# performance types switch-statement

根据https://blogs.msdn.microsoft.com/dotnet/2017/03/09/new-features-in-c-7-0/,对类型使用的switch语句是对订单敏感的:

  

案件条款的顺序现在很重要:就像catch条款一样   案件条款不再必然是不相交的,第一个   这些比赛被选中了。

如果类型上使用的switch语句遵循顺序,我认为它只不过是一个if-else-if链。这个页面https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch也提示了这一点:首先它给出了关于类型的switch语句的示例,然后它说“没有模式匹配,这段代码可能写成如下”并显示{{ 1}}链。

但在我的场景中,类型在继承或接口实现方面是不相关的,因此案例肯定是不相交的。

  1. 编译器是否会发现这一点并自动将if-else-if语句转换为查找表?

  2. 如果没有,有没有办法强制编译器将其转换为查找表?

  3. 情景:

    我正在将xsd.exe从xsd xml架构创建的自动生成的对象结构中的数据解析为我自己的数据结构。因为xsd模式使用了很多选择语句,所以我经常最终使用这种模式:

    switch

    我最近决定优化性能,这就是我对static IContent ParseContent(object c) { // Because of the choice statements in the xsd, the object c can be an instance // of many different (auto-generated) classes which are not related to each other // in terms of inheritance or interface implementation. if (c is class1 c1) // class1 is an auto-generated class from the xsd schema return ParseClass1(c1); else if (c is class2 c2) // class2 is an auto-generated class from the xsd schema return ParseClass2(c2); .... else if (c is class20 c20) // class20 is an auto-generated class from the xsd schema return ParseClass20(c20); else throw new ArgumentException(...); } static MyClass1 ParseClass1(class1 c1) { ... } // MyClass1 implements IContent ... static MyClass20 ParseClass20(class20 c20) { ... } // MyClass20 implements IContent 的机制感兴趣的原因。

1 个答案:

答案 0 :(得分:1)

  
      
  1. 编译器会发现这个并自动将switch语句转换为查找表吗?
  2.   

不,因为它无法保证在将代码编译成DLL后类仍然不相交。

  
      
  1. 如果没有,是否有办法强制编译器将其转换为查找表?
  2.   

如果您始终打开叶子类型,则可以将其转换为类型全名的开关:

switch (c?.GetType().FullName) {
    case "MyNamespace.Class1": {
        return ParseClass1((MyNamespace.Class1)c);
    }
    case "MyNamespace.Class2": {
        return ParseClass2((MyNamespace.Class2)c);
    }
    ...
}

您可以完全取消开关,将其替换为动态调度:

static IContent ParseContent(dynamic c) => ParseClass(c);
//                           ^^^^^^^
// This is the part where "magic" takes place

IContent ParseClass(class1 c) {...}
IContent ParseClass(class2 c) {...}
...
IContent ParseClass(class20 c) {...}
IContent ParseClass(object c) => throw new ArgumentException(...);