21
4

10 回答 10

43

如果DoSomething设置x为 2,那么它们会有所不同。

于 2013-01-16T00:05:18.820 回答
24
[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后假定值为 2 DoSomething(),else 也会使方法退出并且DoSomethingElse()永远不会被调用。在第二种方法中,两种方法都将被调用。

于 2013-01-16T00:27:06.483 回答
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

于 2013-01-16T01:52:06.137 回答
10

当你这样编码时

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

每次条件检查。

但是当你这样编码时

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

如果第一个条件为真,则它不会检查下一个 else if 条件,从而减少不必要的编译

于 2014-09-25T10:48:18.733 回答
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 可能会有所不同。

于 2013-01-16T00:06:45.623 回答
5
于 2017-08-08T20:05:12.923 回答
4

没有关于性能的答案?

所以如果 x=1 那么你在第一种情况下只做一次检查,在第二种情况下你做 2 次检查,所以第一种情况更快。

于 2013-01-16T00:15:47.830 回答
3

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

于 2013-01-16T00:06:17.927 回答
3

当你使用 multipleelse if时,它​​会执行满足的条件。如果还有剩余的情况,它们将被跳过。当您有多个if时,它将检查每个语句。所以这更像是一个性能问题。

于 2013-01-16T00:44:06.680 回答
2

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

于 2013-01-16T00:06:40.400 回答