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

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

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


当前回答

感兴趣的问题。这是几周前在工作中遇到的问题,我们通过编写一个示例片段并在.NET Reflector中查看它找到了答案(Reflector太棒了!!我喜欢它)。

这是我们的发现: 对于字符串以外的任何对象,有效的switch语句将作为switch语句编译到IL。然而,如果它是一个字符串,它在IL中被重写为IF /else IF /else。所以在我们的例子中,我们想知道switch语句如何比较字符串,例如区分大小写等,reflector很快给了我们一个答案。知道这一点很有用。

如果你想对字符串进行区分大小写的比较,那么你可以使用switch语句,因为它比执行String更快。用if/else进行比较。(编辑:阅读哪个更快,打开字符串还是打开类型?然而,如果你想做一个不区分大小写的,那么最好使用if/else,因为结果代码不漂亮。

switch (myString.ToLower())
{
  // not a good solution
}

最好的经验法则是使用switch语句,如果它是有意义的(认真的),例如:

它提高了代码的可读性 您正在比较一个值范围(float, int)或enum

如果您需要操作将值送入switch语句(创建一个用于切换的临时变量),那么您可能应该使用If /else控制语句。

更新:

实际上更好的方法是将字符串转换为大写(例如ToUpper()),因为与ToLower()相比,即时编译器可以做进一步的优化。这是一个微观优化,但在一个紧密的循环中,它可能是有用的。


补充一点:

为了提高switch语句的可读性,可以尝试以下方法:

把最有可能的分支放在前面,即访问最多的分支 如果它们都可能发生,按字母顺序列出,这样更容易找到它们。 永远不要对剩下的最后一个条件使用默认的catch-all,这是懒惰的,并且会在以后的代码生命周期中导致问题。 使用默认的catch-all来断言一个未知的条件,即使它几乎不可能发生。这就是断言的好处。

其他回答

我的计算机教授建议你不要切换语句,因为人们经常忘记断点或错误地使用它。我记不清他到底说了什么,但沿着这条线看了一些开创性的代码库,其中显示了switch语句的例子(几年前),其中也有大量的错误。

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

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

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

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

这实际上并没有回答您的问题,但考虑到编译版本之间的差异很小,我建议您以最能描述您的意图的方式编写代码。这样编译器不仅有更好的机会执行您所期望的操作,而且还会使其他人更容易维护您的代码。

如果您的意图是基于一个变量/属性的值来分支您的程序,那么switch语句最好地代表了这一意图。

如果你的意图是基于不同的变量/属性/条件来分支你的程序,那么If /else If链最能代表这个意图。

我承认cody在人们忘记break命令方面是正确的,但我几乎经常看到人们在犯{}错误的地方执行复杂的if块,因此应该在条件语句中的行却没有。这是我总是在if语句中包含{}的原因之一,即使其中只有一行。它不仅更容易阅读,而且如果我需要在条件语句中添加另一行,我也不会忘记添加它。

题外话,但我经常担心(更经常看到)if/else和switch语句用太多的情况变得太大。这些通常会损害可维护性。

常见的罪魁祸首包括:

在多个if语句中执行太多操作 案例陈述多得人类无法分析 if求值中的条件太多,以至于不知道要寻找什么

修复:

提取到方法重构。 使用带有方法指针的Dictionary而不是大小写,或者使用IoC来增加可配置性。方法工厂也很有帮助。 提取条件到自己的方法

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

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