在c#中使用switch语句和if/else语句的优缺点是什么?除了代码的外观,我无法想象有这么大的区别。

是否有任何原因导致最终的IL或相关的运行时性能会有根本的不同?

相关:什么是更快,开关上字符串或elseif上类型?


当前回答

我认为,不只是c#,而是所有基于C的语言:因为切换仅限于常量,所以使用“跳转表”可以生成非常高效的代码。C用例实际上是一个很好的老式FORTRAN计算GOTO,但c#用例仍然是针对常量进行测试。

优化器不可能生成相同的代码。考虑,例如,

if(a == 3){ //...
} else if (a == 5 || a == 7){ //...
} else {//...
}

因为这些是复合布尔值,生成的代码必须计算一个值,然后短路。现在考虑一下

switch(a){
   case 3: // ...
    break;
   case 5:
   case 7: //...
    break;
   default: //...
}

这可以编译成

BTABL: *
B3:   addr of 3 code
B5:
B7:   addr of 5,7 code
      load 0,1 ino reg X based on value
      jump indirect through BTABL+x

因为你隐式地告诉编译器它不需要计算OR和相等测试。

其他回答

SWITCH语句只在调试或兼容模式下产生与if相同的程序集。在发布版中,它将被编译成跳转表(通过MSIL 'switch'语句),即O(1)。

c#(不像许多其他语言)也允许打开字符串常量——这工作起来有点不同。为任意长度的字符串构建跳转表显然是不现实的,所以通常情况下,这样的切换将被编译成if堆栈。

但是如果条件的数量大到足以覆盖开销,c#编译器将创建一个HashTable对象,用字符串常量填充它,并在该表上进行查找,然后跳转。哈希表查找不是严格的O(1),并且有明显的常量代价,但是如果大小写标签的数量很大,它将比在if中比较每个字符串常量快得多。

总而言之,如果条件数量超过5个左右,则优先选择SWITCH而不是if,否则使用任何看起来更好的方法。

通常它看起来会更好——也就是更容易理解发生了什么。考虑到性能上的好处最少,代码的视图是最重要的区别。

因此,如果if/else看起来更好,就使用它,否则使用switch语句。

根据这个链接,使用Switch和IF语句的迭代测试的IF和Switch比较,就像对于1,000,000,000次迭代,Switch语句花费的时间= 44.3秒,IF语句花费的时间= 48.0秒

也就是每秒20833333次迭代,所以,我们真的需要更专注吗,

附注:只是为了了解在少量条件下的性能差异。

一般来说(考虑到所有语言和所有编译器),switch语句有时可能比if / else语句更有效,因为编译器很容易从switch语句生成跳转表。如果有适当的约束,也可以对if / else语句做同样的事情,但这要困难得多。

在c#的情况下,这也是正确的,但出于其他原因。

对于大量字符串,使用switch语句具有显著的性能优势,因为编译器将使用哈希表来实现跳转。

使用少量的字符串,两者之间的性能是相同的。

这是因为在这种情况下,c#编译器不会生成跳转表。相反,它生成等效于IF / ELSE块的MSIL。

有一个“switch statement”MSIL指令,当被触发时将使用一个跳转表来实现一个switch语句。但是,它只适用于整数类型(这个问题询问的是字符串)。

对于少量的字符串,编译器生成IF / ELSE块比使用哈希表更有效。

当我最初注意到这一点时,我做了一个假设,因为IF / ELSE块用于少量字符串,编译器对大量字符串做了相同的转换。

这是错误的。“IMA”好心地向我指出了这一点(嗯……他不怎么客气,但他是对的,我错了,这是最重要的部分)

我还对MSIL中缺少“switch”指令做了一个愚蠢的假设(我想,如果有一个switch原语,为什么他们不把它与哈希表一起使用,所以一定没有一个switch原语....). 这是错误的,而且我非常愚蠢。IMA再次向我指出了这一点。

我在这里更新是因为这是评分最高的帖子,也是公认的答案。

然而,我把它变成了社区维基,因为我认为我不应该因为犯错而获得REP。如果你有机会,请给ima的帖子投票。

如果你只使用If或else语句基解使用比较?操作符

(value == value1) ? (type1)do this : (type1)or do this;

你可以在开关中执行或程序

switch(typeCode)
{
   case TypeCode:Int32:
   case TypeCode.Int64:
     //dosomething here
     break;
   default: return;
}