Differences between If and ternary operator?:

39

Is there a performance difference between using an if and a ternary operator in C #?

I use Resharper (Productivity Tool for VS) , he insists that ternary operator is better but you do not explain why.

Code, before Refactoring:

if (int.Parse(dr.ItemArray[16].ToString()) == 1)
{
   txt.Append(@"VENDE-SE");
}
else
{
  txt.Append(@"ALUGA-SE");
}

Then:

txt.Append(int.Parse(dr.ItemArray[16].ToString()) == 1
        ? @"VENDE-SE"
        : @"ALUGA-SE");
    
asked by Dorathoto 28.05.2014 в 16:01

2 answers

40

The code

public class Exemplo {
    public static void Main(string[] args) {
        var x = 0;
        if (x == 1) {
            x = 1;
        } else {
            x = 2;
        }
    }
}

is compiled for

.method public hidebysig static 
    void Main (
        string[] args
    ) cil managed 
{
    // Method begins at RVA 0x2050
    // Code size 22 (0x16)
    .maxstack 2
    .locals init (
        [0] int32,
        [1] bool
    )

    IL_0000: nop                  // Do nothing (No operation)
    IL_0001: ldc.i4.0             // Push 0 onto the stack as int32
    IL_0002: stloc.0              // Pop a value from stack into local variable 0
    IL_0003: ldloc.0              // Load local variable 0 onto stack
    IL_0004: ldc.i4.1             // Push 1 onto the stack as int32
    IL_0005: ceq                  // Push 1 (of type int32) if value1 equals value2, else push 0
    IL_0007: stloc.1              // Pop a value from stack into local variable 1
    IL_0008: ldloc.1              // Load local variable 1 onto stack
    IL_0009: brfalse.s IL_0011    // Branch to target if value is zero (false), short form
    IL_000b: nop                  // Do nothing (No operation)
    IL_000c: ldc.i4.1             // Push 1 onto the stack as int32
    IL_000d: stloc.0              // Pop a value from stack into local variable 0
    IL_000e: nop                  // Do nothing (No operation)
    IL_000f: br.s IL_0015         // Branch to target, short form
    IL_0011: nop                  // Do nothing (No operation)
    IL_0012: ldc.i4.2             // Push 2 onto the stack as int32
    IL_0013: stloc.0              // Pop a value from stack into local variable 0
    IL_0014: nop                  // Do nothing (No operation)
    IL_0015: ret                  // Return from method, possibly with a value
} // end of method Exemplo::Main

can be seen in SharpLab .

And the code

public class Exemplo {
    public static void Main(string[] args) {
        var x = 0;
        x = (x == 1 ? 1 : 2);
    }
}

is compiled for

.method public hidebysig static 
    void Main (
        string[] args
    ) cil managed 
{
    // Method begins at RVA 0x2050
    // Code size 13 (0xd)
    .maxstack 2
    .locals init (
        [0] int32
    )

    IL_0000: nop                  // Do nothing (No operation)
    IL_0001: ldc.i4.0             // Push 0 onto the stack as int32
    IL_0002: stloc.0              // Pop a value from stack into local variable 0
    IL_0003: ldloc.0              // Load local variable 0 onto stack
    IL_0004: ldc.i4.1             // Push 1 onto the stack as int32
    IL_0005: beq.s IL_000a        // Branch to target if equal, short form
    IL_0007: ldc.i4.2             // Push 2 onto the stack as int32
    IL_0008: br.s IL_000b         // Branch to target, short form
    IL_000a: ldc.i4.1             // Push 1 onto the stack as int32
    IL_000b: stloc.0              // Pop a value from stack into local variable 0
    IL_000c: ret                  // Return from method, possibly with a value
} // end of method Exemplo::Main

can be seen in SharpLab .

So there is a difference . The difference is just syntactic anyway. But in previous version of this answer there was no difference. So it's implementation detail, you can switch from one version to another.

Contrary to popular belief, the version using the conditional operator can be more efficient .

But it's not that simple. This may not be valid in other situations. I made a simple example. The only way to know what's really going to happen and if it's going to have the same performance is by measuring it. It is checking if it generates the same code in its exact actual situation in the version of the compiler that is used.

And there's more, the JITter can do more optimizations and reverse the situation or leave it in the same condition. / p>

See another comparison example in English .

You can check the raw IL code with ildasm. exe that comes with Visual Studio, or you can use another decompiler like ILSpy , or dotPeek , .Net Reflector or JustDecompile .

You should choose what is best to give understanding to what you want . If you need to use a conditional operator in a complex expression it may be unreadable. On the other hand creating multiple lines in a if to do a simple operation can also be an exaggeration. One tip to improve the legibility of the conditional operator and make it clear that you are putting together an expression is to place parentheses around the complete expression (the three operands as a single thing). Of course there are situations that do not even help.

If there is side effect (change of state), this needs to be clear in the code. It seems to me that in the cases I have presented this it is clear. But there are cases where the code can make it difficult to read the side effect. You should avoid hiding possible misconceptions in the code. The ternary operator is more prone to this. But we should not run away from it at all costs. The pertinence should be observed in the specific case.

Good example:

int resultado = Check() ? 1 : 0;

Bad example:

int resultado = Check1() ? 1 : Check2() ? 1 : Check3() ? 1 : 0;

Although this example can be improved:

int resultado = Check1() ? 1 :
                Check2() ? 1 :
                Check3() ? 1 :
                           0;

One of the advantages of using the conditional operator instead of if is reducing duplicate code. It's good to keep the conciseness . But this can not be at the expense of the legibility of the code. More performance for one side or the other is no advantage . The gain will certainly be small even in the most extraordinary situations. If you really need this small performance gain, C # is not the right language.

Resharper is a great tool (almost mandatory) and gives great suggestions, but it does not code for you. The programmer is always needed to give context to the code. Resharper is not smarter than you and does not know if your code will actually look better the way it suggests. It gives the hint, you decide .

I placed GitHub for future reference.

    
28.05.2014 / 16:21
-1

As far as I know, ReSharper looks at the "simplicity" of if and suggests its "?:" expression to replace if. I believe you have won in perfomance yes, but nothing so significant.

But consider one thing, look at the complete reading of your code and see if this is readable to other programmers. Exacerbated use of this expression can cause confusion in the code reading, hampering further reading for in-app maintenance.

    
28.05.2014 в 16:18