“否则if()”与C#中的多个“if()”相对应

这些实际上有何不同?

// Approach one if (x == 1) DoSomething(); else if (x == 2) DoSomethingElse(); // Approach two if (x == 1) DoSomething(); if (x == 2) DoSomethingElse(); 

生成的CIL是否相同?

使用“if / elseif / else”与“if / else {if / else}”的问题存在,但尚未得到解答。)

如果DoSomethingx设置为2,那么它们将有所不同。

 [STAThread] public static void Main() { Int32 x = 1; if (x == 1) Console.WriteLine("1"); else if (x == 2) Console.WriteLine("2"); } 

结果是:

 .method public hidebysig static void Main() cil managed { .custom instance void [mscorlib]System.STAThreadAttribute::.ctor() .entrypoint .maxstack 2 .locals init ( [0] int32 x) L_0000: ldc.i4.1 L_0001: stloc.0 L_0002: ldloc.0 L_0003: ldc.i4.1 L_0004: bne.un.s L_0011 L_0006: ldstr "1" L_000b: call void [mscorlib]System.Console::WriteLine(string) L_0010: ret L_0011: ldloc.0 L_0012: ldc.i4.2 L_0013: bne.un.s L_001f L_0015: ldstr "2" L_001a: call void [mscorlib]System.Console::WriteLine(string) L_001f: ret } 

而:

 [STAThread] public static void Main() { Int32 x = 1; if (x == 1) Console.WriteLine("1"); if (x == 2) Console.WriteLine("2"); } 

结果是:

 .method public hidebysig static void Main() cil managed { .custom instance void [mscorlib]System.STAThreadAttribute::.ctor() .entrypoint .maxstack 2 .locals init ( [0] int32 x) L_0000: ldc.i4.1 L_0001: stloc.0 L_0002: ldloc.0 L_0003: ldc.i4.1 L_0004: bne.un.s L_0010 L_0006: ldstr "1" L_000b: call void [mscorlib]System.Console::WriteLine(string) L_0010: ldloc.0 L_0011: ldc.i4.2 L_0012: bne.un.s L_001e L_0014: ldstr "2" L_0019: call void [mscorlib]System.Console::WriteLine(string) L_001e: ret } 

IL代码有点不同,这是主要区别:

 Approach One: L_0004: bne.un.s L_0011 -> L_0011: ldloc.0 with L_0010: ret Approach Two: L_0004: bne.un.s L_0010 -> L_0010: ldloc.0 with no ret in between 

当您使用else语句时,与第一种方法一样,只运行满足条件的第一个分支。 另一方面……使用第二种方法处理每个检查,并且将遵循并处理满足条件的每个检查。 这是主要的区别。

这就是为什么在第一种方法的IL代码中,在调用Console.WriteLine之后你有一个“ret”指令,而在第二种方法中它不存在。 在第一种情况下,该方法可以在检查通过后立即退出,因为不再执行对x检查……在第二种方法中,您必须按顺序执行所有这些,这就是为什么ret仅出现在最后方法,到最后没有“捷径”。

对于我的测试,我使用了Console.WriteLine()调用…但是如果DoSomething()涉及x变量的值变化,那么差异在代码行为中绝对更重要。 假设我们将x作为私有静态成员(初始值始终为1)而不是局部变量,并且:

 public void DoSomething() { ++m_X; } 

在第一种方法中,即使在第一次检查后调用DoSomething()之后m_X假定值为2,否则将使方法退出并且永远不会调用DoSomethingElse() 。 在第二种方法中,将调用两种方法。

请注意,在C#中没有else if构造。 您的第一个代码示例与以下内容完全相同:

 if (x == 1) DoSomething(); else { if (x == 2) DoSomethingElse(); } 

由于else只有一个语句,因此可以省略大括号,并且为了增强可读性, if通常与前面的else写在同一行。 编写多个“ else if ”语句相当于进一步嵌套:

 if (x == 1) DoSomething(); else { if (x == 2) DoSomethingElse(); else { if (x == 3) YetSomethingElse(); else { if (x == 4) ReallyDifferent(); } } } 

以上可以写成:

 if (x == 1) DoSomething(); else if (x == 2) DoSomethingElse(); else if (x == 3) YetSomethingElse(); else if (x == 4) ReallyDifferent(); 

从这里,你可以看到链接“ else if ”, if可以产生不同的结果。 在“ else if ”的情况下,将执行满足条件的第一个分支,之后不再进行进一步的检查。 对于链接的if语句,将执行满足其条件的所有分支。

这里的主要区别是当执行分支导致后续条件变为真时。 例如:

  var x = 1; if (x == 1) x = 2; else if (x == 2) x = 3; 

VS

  var x = 1; if (x == 1) x = 2; if (x == 2) x = 3; 

在第一种情况下, x == 2 ,而在第二种情况下, x == 3

当你像这样编码

 // approach two if (x == 1) DoSomething(); if (x == 2) DoSomethingElse(); 

每次条件检查。

但是当你这样编码时

 if (x == 1) DoSomething(); else if (x == 2) DoSomethingElse(); 

如果第一个条件为真,那么它不会检查其他条件,从而减少不必要的编译

当您使用else语句时,只会运行其中一个分支(即第一个满足if条件)。 所有其他if甚至不估计条件:

 // approach one int x = 1; if (x == 1) DoSomething(); //only this will be run, even if `DoSomething` changes `x` to 2 else if (x == 2) DoSomethingElse(); 

当你不使用它时,它们中的每一个都可以运行(取决于每个条件),即每个都是逐个估计的:

 // approach two int x = 1; if (x == 1) DoSomething();//this is run, as `x` == 1 if (x == 2) DoSomethingElse();//if `DoSomething` changes `x` to 2, this is run as well 

所以,IL可能会有所不同。

没有关于性能的问题?

因此,如果x = 1,则在第一种情况下只进行一次检查,在第二种情况下,您进行2次检查,因此第一种情况更快。

如果x改变(在Do Seomthing和DoSomethingElse中),那么第一个语句将只执行一个语句。 在第二个示例中,将检查每个语句(除非编译器将其优化为跳转表以进行数字比较)。

当你使用多个else if ,它将执行满足的条件。 如果有剩余案例,将跳过它们。 当你有多个if ,它会检查每个语句。 所以这更像是一个性能问题。

如果x被多个线程修改,则可能会使用第二种方法调用DoSomething()DoSomethingElse()

否则,只有在第一个条件不成立时才会进行评估。 但是两个连续的if语句都将被评估。

您可以在Python解释器中轻松测试此概念:

首先运行这个:

注意:在Python中,使用elif而不是else

 a = 1 if a >= 1: print('a is greater than or equal to 1') elif a<=1: print('a is less than or equal to 1') 

然后运行这个

 a=1 if a >= 1: print('a is greater than or equal to 1') if a<=1: print('a is less than or equal to 1')