Currently, I'm doing a lot of work in VB.NET...yeah, I know...so if you take a look at my VB code, it has a a bit of a C-hint to it. I guess, I just miss some of the nice language constructs C# has to offer. In particular, the terniary operator (? operator). After making writing several pseudo-terniary statements in VB, I decided to look at the IL that makes up the C# and VB.NET statements. So, let's take a look at the C# statement first:
namespace Lozanotek.Examples
{
using System;
public class TerniaryTest
{
public TerniaryTest() {}
public static void Main()
{
Console.WriteLine(Check(true));
Console.WriteLine(Check(false));
Console.WriteLine(Check(true | false));
Console.ReadLine();
}
public static int Check(bool b)
{
return b ? 1 : 0;
}
public static int Check2(bool b)
{
if (b)
return 1;
else
return 0;
}
}
}
As you can see, Check implements simple terniary logic and Check2 the corresponding if-construct. So, now lets see the IL that the C# compiler emitted:
.method public hidebysig static int32 Check(bool b) cil managed
{
// Code Size: 12 byte(s)
.maxstack 2
.locals (
int32 num1)
L_0000: ldarg.0
L_0001: brtrue.s L_0006
L_0003: ldc.i4.0
L_0004: br.s L_0007
L_0006: ldc.i4.1
L_0007: stloc.0
L_0008: br.s L_000a
L_000a: ldloc.0
L_000b: ret
}
|
|
.method public hidebysig static int32 Check2(bool b) cil managed
{
// Code Size: 13 byte(s)
.maxstack 1
.locals (
int32 num1)
L_0000: ldarg.0
L_0001: brfalse.s L_0007
L_0003: ldc.i4.1
L_0004: stloc.0
L_0005: br.s L_000b
L_0007: ldc.i4.0
L_0008: stloc.0
L_0009: br.s L_000b
L_000b: ldloc.0
L_000c: ret
}
|
As you can see the IL is almost identical! Why? The C# compiler is smart enough to emit the same IL for a simple if-statement when it encounters a terniary-statement. The insteresting thing about this, is that of statement L_0001 on both IL snippets. For the terniary-snippet, the brtrue.s (branch on non-false or non-null) statement is emitted to evaluate value of num1 that's currently in the stack. The evaluation uses the following logic: branch to target if value is non-zero (true). As for the if-snippet, it uses the brfalse.s (branch on false, null, or zero) statement (the converse). Kinda insteresting, isn't it?
Having looked at the C# statements, now lets examine the VB.NET code snippets...
Module IifTest
Sub Main()
Console.WriteLine(Check(True))
Console.WriteLine(Check(False))
Console.WriteLine(Check(True Or False))
End Sub
Function Check(ByVal b As Boolean) As Integer
Return DirectCast(IIf(b, 1, 0), Integer)
End Function
Function Check2(ByVal b As Boolean) As Integer
If b Then
Return 1
Else
Return 0
End If
End Function
End Module
Now, some of you out there that are VB.NET developers might say...What? Why are you using IIf? Don't you know that it evaluates all three expressions, so if one of them is null (or Nothing), it will throw an exception!! In return, all I say, then show me an easier way to get the same result as the terniary operator! They will respond, use an if-statement! So, I ask myself, what's the IL for the VB.NET code? Here's what Reflector told me:
.method public static int32 Check(bool b) cil managed
{
// Code Size: 34 byte(s)
.maxstack 3
.locals (
int32 num1)
L_0000: nop
L_0001: ldarg.0
L_0002: ldc.i4.1
L_0003: box int32
L_0008: ldc.i4.0
L_0009: box int32
L_000e: call object [Microsoft.VisualBasic]Microsoft.VisualBasic.Interaction::IIf(bool, object, object)
L_0013: unbox int32
L_0018: ldobj int32
L_001d: stloc.0
L_001e: br.s L_0020
L_0020: ldloc.0
L_0021: ret
}
|
|
.method public static int32 Check2(bool b) cil managed
{
// Code Size: 18 byte(s)
.maxstack 1
.locals (
int32 num1)
L_0000: nop
L_0001: ldarg.0
L_0002: brfalse.s L_000a
L_0004: ldc.i4.1
L_0005: stloc.0
L_0006: br.s L_0010
L_0008: br.s L_000f
L_000a: nop
L_000b: ldc.i4.0
L_000c: stloc.0
L_000d: br.s L_0010
L_000f: nop
L_0010: ldloc.0
L_0011: ret
}
|
.method public static object IIf(bool Expression, object TruePart, object FalsePart) cil managed
{
// Code Size: 7 byte(s)
.maxstack 1
.locals (
object obj1)
L_0000: ldarg.0
L_0001: brfalse.s L_0005
L_0003: ldarg.1
L_0004: ret
L_0005: ldarg.2
L_0006: ret
}
|
If you take a look at the IL code emitted from the VB.NET compiler, you can see that the in the iif-snippet, the call to the IIf construct is cleary visible (with a lot of boxing and unboxing for type conversion) and in the if-snippet, you have a lot more IL than the C# version of the if-statement! The thing I like the most about the VB.NET if-snippet, is the fact that it uses the nop (no operation) instruction, which essentially does nothing! If you look at the IIf IL snippet, you as yourself...why doesn't the VB.NET compiler just emit that same IL for the if-statement? All, I have to say, well...that's VB for ya!