这些实际上有何不同?
// Approach one
if (x == 1)
DoSomething();
else if (x == 2)
DoSomethingElse();
// Approach two
if (x == 1)
DoSomething();
if (x == 2)
DoSomethingElse();
生成的CIL是否相同?
(问题 Use of “if/elseif/else” versus “if/else{if/else}” 存在,但尚未得到解答。)
答案 0 :(得分:39)
如果DoSomething
将x
设置为2,则它们会有所不同。
答案 1 :(得分:21)
[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;
}
在第一种方法中,即使m_X
在第一次检查后调用DoSomething()
后假定值为2,否则将退出该方法并且永远不会调用DoSomethingElse()
。在第二种方法中,将调用两种方法。
答案 2 :(得分:14)
请注意,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
。
答案 3 :(得分:9)
当你像这样编码时
// approach two
if (x == 1)
DoSomething();
if (x == 2)
DoSomethingElse();
每次条件检查。
但是当你像这样编码时
if (x == 1)
DoSomething();
else if (x == 2)
DoSomethingElse();
如果第一个条件为真,则不会检查其他条件,从而减少不必要的编译。
答案 4 :(得分:5)
当您使用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可能会有所不同。
答案 5 :(得分:4)
没有关于性能的答案?
因此,如果x = 1,则在第一种情况下只进行一次检查,在第二种情况下,您进行2次检查,因此第一种情况更快。
答案 6 :(得分:3)
如果x改变(在Do Seomthing和DoSomethingElse中),那么第一个语句将只执行一个语句。在第二个示例中,将检查每个语句(除非编译器将其优化为跳转表以进行数字比较)。
答案 7 :(得分:3)
当您使用多个else if
时,它将执行满足的条件。如果有剩余案例,将跳过它们。当您有多个if
时,它会检查每个语句。所以这更像是一个性能问题。
答案 8 :(得分:3)
否则,只有在第一个条件不成立时才会进行评估。但是两个连续的if语句都将被评估。
您可以在Python interpreter:
中轻松测试此概念首先运行:
注意:在Python中,如果
,则使用elif代替elsea = 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')
答案 9 :(得分:2)
如果多个线程修改了x
,则可能会使用第二种方法调用DoSomething()
和DoSomethingElse()