“else if()” versus multiple “if()”s in C#

后端 未结 10 1787
一个人的身影
一个人的身影 2021-01-03 21:51

How do these practically differ?

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

// Approach two
if (x == 1)
    DoSo         


        
相关标签:
10条回答
  • 2021-01-03 22:43

    When you use multiple else if, it will execute the condition that meets. If there are remaining cases, they will be skipped. When you have multiple if, it will check every statement. So this becomes more of a performance issue.

    0 讨论(0)
  • 2021-01-03 22:46

    No anwsers about performance?

    So if x=1 then you do only one check in first case, and in second case you do 2 checks, so first case is faster.

    0 讨论(0)
  • 2021-01-03 22:52

    When you use else statement, only one of the branches will be run (i.e. the first, which meets the if condition). All other if conditions won't even be estimated:

    // 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();
    

    While when you don't use it each of them may be run (depending on each of the conditions), i.e. each of them is estimated one by one:

    // 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
    

    So, IL may differ.

    0 讨论(0)
  • 2021-01-03 22:54
    [STAThread]
    public static void Main()
    {
        Int32 x = 1;
    
        if (x == 1)
            Console.WriteLine("1");
        else if (x == 2)
            Console.WriteLine("2");
    }
    

    Results in:

    .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 
    }
    

    While:

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

    Results in:

    .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 code is a little bit different and here is the main difference:

    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
    

    When you use else statement, as in first approach, only the first branch that meets the condition will be run. On the other hand... with the second approach every check is processed and every check that meets the condition will be followed and processed. That's the main difference.

    That's why in the first approach's IL code you have a "ret" directive just after the call of Console.WriteLine while in the second it's not present. In the first case the method can be exited just after a check has been passed because no more checks on x will be performed... in the second approach you have to follow all of them sequentially and that's why ret is only appearing at the end of the method, no "shortcuts" to the end.

    For my test i used a Console.WriteLine() call... but it's sure that if DoSomething() involves a value change of x variable, the difference will be absolutely more important in the code behavior. Let's say that we have x as a private static member (initial value always 1) instead of a local variable and:

    public void DoSomething()
    {
        ++m_X;
    }
    

    In the first approach, even if m_X assumes a value of 2 after DoSomething() is called thanks to the first check, else will make the method exit and DoSomethingElse() will never be called. In the second approach both methods will be called.

    0 讨论(0)
提交回复
热议问题