在C#中使用switch
语句与if/else
的好处/缺点是什么?我无法想象除了你的代码外观之外还有其他重大差异。
为什么生成的IL或相关的运行时性能会有根本的不同?
答案 0 :(得分:302)
SWITCH语句仅在调试或兼容模式下生成与IF相同的程序集。在发布中,它将被编译成跳转表(通过MSIL'witch'语句) - 这是O(1)。
C#(与许多其他语言不同)也允许打开字符串常量 - 这有点不同。为任意长度的字符串构建跳转表显然是不切实际的,因此大多数情况下这样的开关将被编译成IF堆栈。
但是如果条件的数量足以覆盖开销,C#编译器将创建一个HashTable对象,用字符串常量填充它并在该表上进行查找,然后跳转。 Hashtable查找不是严格的O(1)并且具有明显的恒定成本,但是如果案例标签的数量很大,则它将比IF中的每个字符串常量快得多。
总结一下,如果条件数超过5个,则选择SWITCH而不是IF,否则使用看起来更好的东西。
答案 1 :(得分:48)
通常(考虑所有语言和所有编译器),switch语句CAN SOMETIMES比if / else语句更有效,因为编译器很容易从switch语句生成跳转表。在适当的约束下,if / else语句可以做同样的事情,但这要困难得多。
对于C#,情况也是如此,但出于其他原因。
使用大量字符串时,使用switch语句有明显的性能优势,因为编译器将使用哈希表来实现跳转。
使用少量字符串,两者之间的性能是相同的。
这是因为在这种情况下C#编译器不会生成跳转表。相反,它生成的MSIL等同于IF / ELSE块。
有一个“switch语句”MSIL指令,当jitted将使用跳转表来实现switch语句。它只适用于整数类型(但这个问题询问字符串)。
对于少量字符串,编译器生成IF / ELSE块效率更高,然后使用哈希表。
当我最初注意到这一点时,我假设因为IF / ELSE块与少量字符串一起使用,编译器对大量字符串进行了相同的转换。
这是错误的。 'IMA'非常友好地指出了这一点(嗯......他对此不好,但他是对的,我错了,这是重要的部分)
我还对MSIL中缺少“切换”指令做了一个假设(我想,如果有一个切换原语,他们为什么不用哈希表使用它,所以一定不能有切换原语....)。这既错了,又让我非常愚蠢。再次'IMA'向我指出了这一点。
我在这里做了更新,因为它是评分最高的帖子和接受的答案。
然而,我已经把它作为社区维基,因为我觉得我不配错了REP。如果你有机会,请投票'ima'的帖子。
答案 2 :(得分:17)
偏好switch
的三个理由:
针对本机代码的编译器通常可以将switch语句编译为一个条件分支加上间接跳转,而if
s序列需要条件序列分支即可。根据案件的密度,已经写了很多关于如何有效地编写案例陈述的学术论文;有些是从lcc compiler page链接的。 (Lcc有一个更具创新性的交换机编译器。)
switch语句是互斥备选方案中的选择,并且切换语法使该控制流程对程序员更加透明然后是if-then的嵌套 - 陈述。
在某些语言中,包括绝对ML和Haskell,编译器会检查您是否遗漏了任何案例。我认为这个功能是ML和Haskell的主要优点之一。我不知道C#是否可以做到这一点。
一则轶事:在他获得终身成就奖的演讲中,我听到Tony Hoare说他在职业生涯中所做的一切,有三件他最为自豪:
case
语句)我无法想象没有switch
的生活。
答案 3 :(得分:14)
实际上,switch语句更有效。编译器会将它优化为一个查找表,其中if / else语句不能。缺点是switch语句不能与变量值一起使用 你做不到:
switch(variable)
{
case someVariable
break;
default:
break;
}
必须是
switch(variable)
{
case CONSTANT_VALUE;
break;
default:
break;
}
答案 4 :(得分:14)
编译器会将几乎所有内容优化到相同的代码中,只有很小的差异(Knuth,任何人?)。
不同之处在于,如果将else语句串在一起,则switch语句比十五个更清晰。
朋友不要让朋友堆叠if-else语句。
答案 5 :(得分:12)
我没有看到其他人提出(显而易见的?)这一点,即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”代码的速度可以是基于交换机的代码的两倍。即使编译器将“开关”转换为某种聪明的表驱动goto,它仍然不会像检查零那样快。
答案 6 :(得分:7)
通常会看起来更好 - 也就是说会更容易理解发生了什么。考虑到性能优势最多只是极其微小,代码视图是最重要的区别。
因此,如果if / else看起来更好,请使用它,否则使用switch语句。
答案 7 :(得分:4)
附带主题,但我经常担心(并且经常看到)if
/ else
和switch
语句过于庞大且案例太多。这些通常会损害可维护性。
常见的罪魁祸首包括:
修复:
答案 8 :(得分:3)
如果您只是使用if或else语句,基本解决方案正在使用比较?操作
(value == value1) ? (type1)do this : (type1)or do this;
您可以在开关中执行或例程
switch(typeCode)
{
case TypeCode:Int32:
case TypeCode.Int64:
//dosomething here
break;
default: return;
}
答案 9 :(得分:2)
根据此链接,IF vs Switch使用switch和if语句进行迭代测试的比较,类似于1,000,000,000次迭代,切换语句= 43.0s &通过如果声明 = 48.0s
每秒迭代次数 20833333 ,那么,我们是否真的需要关注更多,
P.S:只知道小条件列表的性能差异。
答案 10 :(得分:2)
这实际上并没有回答你的问题,但考虑到编译版本之间没有什么区别,我建议你以最能描述你意图的方式编写代码。编译器不仅有更好的机会按照您的期望进行操作,而且还可以让其他人更轻松地维护您的代码。
如果您打算根据一个变量/属性的值来分支您的程序,那么switch语句最能代表该意图。
如果您打算根据不同的变量/属性/条件来分支您的程序,那么if / else if chain最能代表该意图。
我会认为cody对于人们忘记break命令是正确的,但是我几乎经常看到人们在他们得到{}错误的块时做复杂,所以应该在条件语句中的行不是。这是我总是在我的if语句中包含{}的原因之一,即使其中有一行。它不仅更容易阅读,而且如果我需要在条件中添加另一行,我不能忘记添加它。
答案 11 :(得分:2)
switch语句肯定比if if if更快。 BlackWasp提供了最快的速度
http://www.blackwasp.co.uk/SpeedTestIfElseSwitch.aspx
- 检查出来
但在很大程度上取决于你想要考虑的可能性,但我尽可能尝试使用switch语句。
答案 12 :(得分:1)
不仅仅是C#,而是所有基于C的语言,我认为:因为开关仅限于常量,所以可以使用“跳转表”生成非常高效的代码。 C案例实际上是一个很好的旧FORTRAN计算GOTO,但C#案例仍然是针对常量的测试。
优化器不能生成相同的代码。考虑一下,例如,
if(a == 3){ //...
} else if (a == 5 || a == 7){ //...
} else {//...
}
因为那些是复合布尔值,所生成的代码必须计算一个值和shortcircuit。现在考虑等效的
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和相等测试。
答案 13 :(得分:1)
兴趣问题。这是几个星期前在工作中出现的,我们通过编写一个示例片段并在.NET Reflector中查看它来找到答案(反射器真棒!我喜欢它)。
这是我们发现的: 除字符串以外的任何内容的有效switch语句将作为switch语句编译为IL。但是,如果它是一个字符串,它将被重写为IL中的if / else if / else。所以在我们的例子中,我们想知道switch语句如何比较字符串,例如区分大小写等,而反射器很快给了我们一个答案。知道这很有用。
如果你想对字符串进行区分大小写的比较,那么 可以 使用switch语句,因为它比在if / else中执行String.Compare更快。 (编辑:阅读What is quicker, switch on string or elseif on type?进行一些实际的性能测试)但是如果你想做一个不区分大小写的话,最好使用if / else,因为结果代码并不漂亮。
switch (myString.ToLower())
{
// not a good solution
}
最好的经验法则是使用switch语句(严重),例如:
如果你需要操纵值来输入switch语句(创建一个临时变量来切换),那么你可能应该使用if / else控制语句。
更新:
将字符串转换为大写(例如ToUpper()
)实际上更好,因为显然还有进一步的优化,即即时编译器可以像ToLower()
那样进行优化。这是一个微观优化,但在紧密循环中它可能是有用的。
一点注意事项:
要提高switch语句的可读性,请尝试以下操作:
答案 14 :(得分:0)
我刚注意到的一点是你可以组合if / else和switch语句!在需要检查前置条件时非常有用。
if (string.IsNullOrEmpty(line))
{
//skip empty lines
}
else switch (line.Substring(0,1))
{
case "1":
Console.WriteLine(line);
break;
case "9":
Console.WriteLine(line);
break;
default:
break;
}
答案 15 :(得分:0)
我的cs教授建议不要切换语句,因为人们常常忘记中断或使用不正确。我无法回想起他所说的内容,但是我看到一些开创性的代码库,其中显示了switch语句的例子(多年前)也有很多错误。
答案 16 :(得分:0)
我认为开关比条件更快 比如看看是否有类似的程序:
写一个程序输入任意数字(介于1 - 99之间)并检查它是在哪个插槽中a)1 - 9然后插槽1 b)11 - 19然后插槽2 c)21-29然后插槽3依此类推直到89-99
然后如果你必须做出很多条件,那么你必须输入儿子切换案例
切换(否/ 10)
且案例0 = 1-9,案例1 = 11-19,依此类推
它会如此简单
还有更多这样的例子!
答案 17 :(得分:0)
switch语句基本上是对等的比较。键盘事件比switch语句有很大的优势,当易于编写和读取代码然后if ifif语句时,错过{bracket}也会让人感到麻烦。
char abc;
switch(abc)
{
case a: break;
case b: break;
case c: break;
case d: break;
}
如果(theAmountOfApples大于5&& theAmountOfApples小于10),if elseif语句对于多个解决方案非常有用保存你的苹果 否则if(theAmountOfApples大于10 || theAmountOfApples == 100)卖掉你的苹果。我不写c#或c ++,但在学习java之前我确实学过它,而且它们是接近的语言。
答案 18 :(得分:0)
我知道这不是问题,但我真的需要指出的是,当您考虑该级别的效率时,您可能需要在代码中进行更多抽象。您将不再需要切换案例,特别是如果它包含逻辑。 (我在php中的例子)。
$feeMapping = [
1000 => 1,
2000 => 2,
3000 => 3,
4000 => 4,
5000 => 5,
6000 => 6,
7000 => 7
];
function findFee($feeMapping, $amount) {
foreach ($feeMapping as $fee => $value) {
if ($value >= $amount) {
return $fee;
}
}
return 7;
}
$feeValue = findFee($feeMapping, 200);
现在看看类似代码的冗余!
if ($amount >= 1000) {
return 1;
} elseif ($amount >= 2000) {
return 2;
} elseif ($amount >= 3000) {
return 3;
} elseif ($amount >= 4000) {
return 4;
} elseif ($amount >= 5000) {
return 5;
} elseif ($amount >= 6000) {
return 6;
} else {
return 7;
}
答案 19 :(得分:0)
switch语句的一个可能缺点是缺少多个条件。对于具有不同条件的if(else)但不是多个case语句,您可以有多个条件。
Switch语句不适用于超出简单布尔方程/表达式范围的逻辑运算。对于那些布尔方程/表达式,它非常适合但不适用于其他逻辑运算。
对于If语句中可用的逻辑,您有更多自由,但如果If语句变得难以处理或处理不当,则可读性会受到影响。
根据你所面对的情况,两者都有。
答案 20 :(得分:-1)
我的2美分就可以了。在大多数情况下,如果性能不是一个标准,那么它更多地是关于代码的可读性。如果if / else语句的数量比使用switch语句的数量要多。