在 C# 中使用 if/else 和 switch-case 之间有什么显着区别吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/395618/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is there any significant difference between using if/else and switch-case in C#?
提问by Matthew M. Osborn
What is the benefit/downside to using a switch
statement vs. an if/else
in C#. I can't imagine there being that big of a difference, other than maybe the look of your code.
在 C# 中使用switch
语句与 an的好处/缺点是什么if/else
。除了代码的外观之外,我无法想象有那么大的差异。
Is there any reason why the resulting IL or associated runtime performance would be radically different?
是否有任何原因导致产生的 IL 或相关的运行时性能会完全不同?
Related: What is quicker, switch on string or elseif on type?
相关:什么更快,打开字符串还是打开类型?
采纳答案by ima
SWITCH statement only produces same assembly as IFs in debug or compatibility mode. In release, it will be compiled into jump table (through MSIL 'switch' statement)- which is O(1).
SWITCH 语句仅在调试或兼容模式下生成与 IF 相同的程序集。在发布时,它会被编译成跳转表(通过 MSIL 'switch' 语句)——这是 O(1)。
C# (unlike many other languages) also allows to switch on string constants - and this works a bit differently. It's obviously not practical to build jump tables for strings of arbitrary lengths, so most often such switch will be compiled into stack of IFs.
C#(与许多其他语言不同)还允许打开字符串常量——这有点不同。为任意长度的字符串构建跳转表显然是不切实际的,所以大多数情况下这样的开关会被编译成 IF 堆栈。
But if number of conditions is big enough to cover overheads, C# compiler will create a HashTable object, populate it with string constants and make a lookup on that table followed by jump. Hashtable lookup is not strictly O(1) and has noticeable constant costs, but if number of case labels is large, it will be significantly faster than comparing to each string constant in IFs.
但是如果条件的数量足够大以覆盖开销,C# 编译器将创建一个 HashTable 对象,用字符串常量填充它并在该表上进行查找,然后跳转。哈希表查找不是严格的 O(1) 并且具有明显的恒定成本,但是如果案例标签的数量很大,它将比与 IF 中的每个字符串常量进行比较要快得多。
To sum it up, if number of conditions is more than 5 or so, prefer SWITCH over IF, otherwise use whatever looks better.
总而言之,如果条件数量超过 5 个左右,则更喜欢 SWITCH 而不是 IF,否则使用看起来更好的。
回答by kemiller2002
Actually, a switch statement is more efficient. The compiler will optimize it to a look up table where with if/else statements it cannot. The down side is that a switch statement can't be used with variable values.
You can't do:
实际上,switch 语句更有效。编译器会将其优化为一个查找表,其中使用 if/else 语句则不能。不利的一面是 switch 语句不能与变量值一起使用。
你不能这样做:
switch(variable)
{
case someVariable
break;
default:
break;
}
it has to be
它一定要是
switch(variable)
{
case CONSTANT_VALUE;
break;
default:
break;
}
回答by Charlie Martin
Not just C#, but all C-based languages, I think: because a switch is limited to constants, it's possible to generate very efficient code using a "jump table". The C case is really a good old FORTRAN computed GOTO, but the C# case is still tests against a constant.
我认为不仅是 C#,而且是所有基于 C 的语言:因为开关仅限于常量,所以可以使用“跳转表”生成非常有效的代码。C 案例确实是一个很好的旧 FORTRAN 计算 GOTO,但 C# 案例仍然是针对常量的测试。
It is not the case that the optimizer will be able to make the same code. Consider, eg,
优化器无法生成相同的代码。考虑,例如,
if(a == 3){ //...
} else if (a == 5 || a == 7){ //...
} else {//...
}
Because those are compound booleans, the generated code has to compute a value, and shortcircuit. Now consider the equivalent
因为这些是复合布尔值,所以生成的代码必须计算一个值,然后短路。现在考虑等价的
switch(a){
case 3: // ...
break;
case 5:
case 7: //...
break;
default: //...
}
This can be compiled into
这可以编译成
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
because you are implicitly telling the compiler that it doesn't need to compute the OR and equality tests.
因为您隐含地告诉编译器它不需要计算 OR 和相等性测试。
回答by Charlie Martin
The compiler is going to optimize pretty much everything into the same code with minor differences (Knuth, anyone?).
编译器会将几乎所有内容优化为相同的代码,但有细微差别(Knuth,有人吗?)。
The difference is that a switch statement is cleaner than fifteen if else statements strung together.
不同之处在于 switch 语句比串在一起的 15 个 if else 语句更简洁。
Friends don't let friends stack if-else statements.
朋友不要让朋友堆叠 if-else 语句。
回答by gbjbaanb
often it will look better - ie will be easier to understand what's going on. Considering the performance benefit will be extremely minimal at best, the view of the code is the most important difference.
通常它看起来会更好 - 即会更容易理解发生了什么。考虑到性能优势充其量只能是极小的,代码的视图是最重要的区别。
So, if the if/else looks better, use it, otherwise use a switch statement.
因此,如果 if/else 看起来更好,请使用它,否则使用 switch 语句。
回答by gbjbaanb
My cs professor suggested not to you switch statements since so often people forgot the break or use it incorrectly. I can;t recall exactly what he said but something along the lines that looking at some seminal code base that showed examples of the switch statement (years ago) had a tons of mistakes in it also.
我的 cs 教授建议你不要切换语句,因为人们经常忘记中断或错误地使用它。我不记得他说了什么,但是在查看一些显示 switch 语句示例的开创性代码库(几年前)中也有很多错误。
回答by Scott Wisniewski
In general (considering all languages and all compilers) a switch statement CAN SOMETIMES be more efficient than an if / else statement, because it is easy for a compiler to generate jump tables from switch statements. It is possible to do the same thing for if / else statements, given appropriate constraints, but that is much more difficult.
一般来说(考虑到所有语言和所有编译器)switch 语句有时比 if / else 语句更有效,因为编译器很容易从 switch 语句生成跳转表。如果有适当的约束,可以对 if / else 语句做同样的事情,但这要困难得多。
In the case of C#, this is also true, but for other reasons.
在 C# 的情况下,这也是正确的,但出于其他原因。
With a large number of strings, there is a significant performance advantage to using a switch statement, because the compiler will use a hash table to implement the jump.
对于大量字符串,使用 switch 语句有显着的性能优势,因为编译器会使用哈希表来实现跳转。
With a small number of strings, the performance between the two is the same.
使用少量的字符串,两者之间的性能是相同的。
This is because in that case the C# compiler does not generate a jump table. Instead it generates MSIL that is equivalent to IF / ELSE blocks.
这是因为在这种情况下,C# 编译器不会生成跳转表。相反,它生成等效于 IF / ELSE 块的 MSIL。
There is a "switch statement" MSIL instruction that when jitted will use a jump table to implement a switch statement. It only works with integer types, however (this question asks about strings).
有一个“switch statement”MSIL指令,当jitted时会使用一个跳转表来实现一个switch语句。但是,它仅适用于整数类型(此问题询问字符串)。
For small numbers of strings, it's more efficient for the compiler to generate IF / ELSE blocks then it is to use a hash table.
对于少量字符串,编译器生成 IF / ELSE 块比使用哈希表更有效。
When I originally noticed this, I made the assumption that because IF / ELSE blocks were used with a small number of strings, that the compiler did the same transformation for large numbers of strings.
当我最初注意到这一点时,我假设因为 IF / ELSE 块与少量字符串一起使用,编译器对大量字符串进行了相同的转换。
This was WRONG. 'IMA' was kind enough to point this out to me (well...he wasn't kind about it, but he was right, and I was wrong, which is the important part)
这是错误的。'IMA' 很友好地向我指出了这一点(嗯......他对此并不友好,但他是对的,而我错了,这是重要的部分)
I also made a bone headed assumption about the lack of a "switch" instruction in MSIL (I figured, if there was a switch primitive, why weren't they using it with a hash table, so there must not be a switch primitive.... ). This was both wrong, and incredibly stupid on my part. Again 'IMA' pointed this out to me.
我还对 MSIL 中缺少“switch”指令做了一个愚蠢的假设(我想,如果有一个 switch 原语,为什么他们不将它与哈希表一起使用,所以一定没有 switch 原语。 ……)。这对我来说既是错误的,也是非常愚蠢的。'IMA' 再次向我指出了这一点。
I made the updates here because it's the highest rated post, and the accepted answer.
我在这里进行了更新,因为它是评分最高的帖子,也是公认的答案。
However,I've made it Community Wiki because I figure I don't deserve the REP for being wrong. If you get a chance, please up vote 'ima''s post.
但是,我已将其设为 Community Wiki,因为我认为我不应该因为错误而受到 REP。如果有机会,请为“ima”的帖子投上一票。
回答by Chris Brandsma
Side topic, but I often worry about (and more often see) if
/else
and switch
statement get way too large with too many cases. These often hurt maintainability.
附带话题,但我经常担心(并且更经常看到)if
/else
和switch
语句在太多情况下变得太大。这些通常会损害可维护性。
Common culprits include:
常见的罪魁祸首包括:
- Doing too much inside of multiple if statements
- More case statements than humanly possible to analyze
- Too many conditions in the if evaluation to know what is being looked for
- 在多个 if 语句中做太多事情
- 比人类可能分析的更多的案例陈述
- if 评估中的条件太多,无法知道正在寻找什么
To fix:
修理:
- Extract to Method refactoring.
- Use a Dictionary with method pointers instead of a case, or use an IoC for added configurability. Method factories also can be helpful.
- Extract the conditions to their own method
- 提取到方法重构。
- 使用带有方法指针的字典而不是大小写,或者使用 IoC 来增加可配置性。方法工厂也很有帮助。
- 提取条件到自己的方法
回答by dj_segfault
This doesn't actually answer your question, but given there will be little difference between the compiled versions, I would urge you to write your code in a way that best describes your intentions. Not only is there a better chance of the compiler doing what you expect, but it will make it easier for others to maintain your code.
这实际上并没有回答您的问题,但鉴于编译版本之间几乎没有区别,我建议您以最能描述您的意图的方式编写代码。不仅编译器有更好的机会做你期望的事情,而且它会让其他人更容易维护你的代码。
If your intention is to branch your program based on the value of one variable/attribute, then a switch statement best represents that intention.
如果您的意图是根据一个变量/属性的值对程序进行分支,那么 switch 语句最能代表该意图。
If your intention is to branch your program based on different variables/attributes/conditions, then a if/else if chain best represents that intention.
如果您的意图是根据不同的变量/属性/条件分支您的程序,那么 if/else if 链最能代表该意图。
I will grant that cody is right about people forgetting the break command, but almost as frequently I see people doing complicated if blocks where they get the { } wrong, so lines that should be in the conditional statement are not. It's one of the reasons I alwaysinclude { } on my if statements even if there's one line in it. Not only is it easier to read, but if I need to add another line in the conditional, I can't forget to add it.
我承认 cody 关于人们忘记 break 命令是正确的,但几乎我经常看到人们做复杂的 if 块在他们得到 { } 错误的地方,所以应该在条件语句中的行不是。这是我总是在 if 语句中包含 { }的原因之一,即使其中只有一行。不仅更容易阅读,而且如果我需要在条件中添加另一行,我不能忘记添加它。
回答by Norman Ramsey
Three reasons to prefer the switch
:
选择 的三个理由switch
:
A compiler targeting native code can often compile a switch statement into one conditional branch plus an indirect jumpwhereas a sequence of
if
s 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 alternativesand the switch syntax makes this control flow more transparent to the programmerthen 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 语句编译为一个条件分支和一个间接跳转,而
if
s序列需要一系列条件分支。根据案例的密度,已经写了很多关于如何有效地编译案例陈述的学术论文;有些是从lcc 编译器页面链接的。(Lcc 拥有用于开关的更具创新性的编译器之一。)switch 语句是在互斥选项中的一个选择,并且 switch 语法使这个控制流对程序员更透明,而不是嵌套的 if-then-else 语句。
在某些语言中,绝对包括 ML 和 Haskell,编译器会检查您是否遗漏了任何情况。我认为这个特性是 ML 和 Haskell 的主要优势之一。我不知道 C# 是否可以做到这一点。
An anecdote: at a lecture he gave on receiving an award for lifetime achievement, I heard Tony Hoare say that of all the things he did in his career, there were three that he was most proud of:
轶事:在他关于获得终身成就奖的演讲中,我听到托尼·霍尔说,在他职业生涯中所做的所有事情中,他最引以为豪的是三件事:
- Inventing Quicksort
- Inventing the switch statement (which Tony called the
case
statement) - Starting and ending his career in industry
- 发明快速排序
- 发明 switch 语句(托尼称之为
case
语句) - 开始和结束他的工业生涯
I can't imagine living without switch
.
我无法想象没有switch
.