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

时间:2013-01-16 00:04:40

标签: c#

这些实际上有何不同?

// 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}” 存在,但尚未得到解答。)

10 个答案:

答案 0 :(得分:39)

如果DoSomethingx设置为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代替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')

答案 9 :(得分:2)

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