在c#中使用switch语句和if/else语句的优缺点是什么?除了代码的外观,我无法想象有这么大的区别。
是否有任何原因导致最终的IL或相关的运行时性能会有根本的不同?
相关:什么是更快,开关上字符串或elseif上类型?
在c#中使用switch语句和if/else语句的优缺点是什么?除了代码的外观,我无法想象有这么大的区别。
是否有任何原因导致最终的IL或相关的运行时性能会有根本的不同?
相关:什么是更快,开关上字符串或elseif上类型?
当前回答
我没有看到其他人提出(明显的?)观点,即switch语句的假设效率优势取决于各种情况的可能性近似相等。在一个(或几个)值更有可能的情况下,if-then-else阶梯可以更快,通过确保首先检查最常见的情况:
举个例子:
if (x==0) then {
// do one thing
} else if (x==1) {
// do the other thing
} else if (x==2) {
// do the third thing
}
vs
switch(x) {
case 0:
// do one thing
break;
case 1:
// do the other thing
break;
case 2:
// do the third thing
break;
}
如果x在90%的时间为零,“If -else”代码的速度可以是基于开关的代码的两倍。即使编译器将“switch”转换为某种聪明的表驱动的goto,它仍然不会像简单地检查零那样快。
其他回答
题外话,但我经常担心(更经常看到)if/else和switch语句用太多的情况变得太大。这些通常会损害可维护性。
常见的罪魁祸首包括:
在多个if语句中执行太多操作 案例陈述多得人类无法分析 if求值中的条件太多,以至于不知道要寻找什么
修复:
提取到方法重构。 使用带有方法指针的Dictionary而不是大小写,或者使用IoC来增加可配置性。方法工厂也很有帮助。 提取条件到自己的方法
我认为Switch比If条件更快 看看是否有这样一个程序:
写一个程序,输入任意数字(1- 99之间),并检查它在哪个槽a) 1- 9,然后槽1 b) 11 - 19,然后槽2 c) 21-29,然后槽3,直到89-99
然后,如果你有许多条件,但儿子切换情况下,你必须只是类型
开关(no /10) case 0 = 1-9,case 1 = 11-19,以此类推
这将是如此简单
还有很多这样的例子!
一般来说(考虑到所有语言和所有编译器),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的帖子投票。
有三个理由支持这种转变:
A compiler targeting native code can often compile a switch statement into one conditional branch plus an indirect jump whereas a sequence of ifs requires a sequence of conditional branches. Depending on the density of cases a great many learned papers have been written about how to compile case statements efficiently; some are linked from the lcc compiler page. (Lcc had one of the more innovative compilers for switches.) A switch statement is a choice among mutually exclusive alternatives and the switch syntax makes this control flow more transparent to the programmer then a nest of if-then-else statements. In some languages, including definitely ML and Haskell, the compiler checks to see if you have left out any cases. I view this feature as one of the major advantages of ML and Haskell. I don't know if C# can do this.
一个趣闻:在托尼·霍尔接受终身成就奖的演讲中,我听到他说,在他职业生涯中所做的所有事情中,有三件事是他最自豪的:
发明快速排序 发明switch语句(Tony称之为case语句) 开始和结束他的工业生涯
我无法想象没有开关的生活。
SWITCH语句只在调试或兼容模式下产生与if相同的程序集。在发布版中,它将被编译成跳转表(通过MSIL 'switch'语句),即O(1)。
c#(不像许多其他语言)也允许打开字符串常量——这工作起来有点不同。为任意长度的字符串构建跳转表显然是不现实的,所以通常情况下,这样的切换将被编译成if堆栈。
但是如果条件的数量大到足以覆盖开销,c#编译器将创建一个HashTable对象,用字符串常量填充它,并在该表上进行查找,然后跳转。哈希表查找不是严格的O(1),并且有明显的常量代价,但是如果大小写标签的数量很大,它将比在if中比较每个字符串常量快得多。
总而言之,如果条件数量超过5个左右,则优先选择SWITCH而不是if,否则使用任何看起来更好的方法。