Does the VB.NET “If” operator cause boxing?

后端 未结 2 1200
孤街浪徒
孤街浪徒 2020-12-20 11:19

Those of us who\'ve worked in VB/VB.NET have seen code similar to this abomination:

Dim name As String = IIf(obj Is Nothing, \"\", obj.Name)
<
相关标签:
2条回答
  • 2020-12-20 12:08

    The main thing is that you correctly identified the new If as an operator rather than a function. It is also typesafe and therefore does not need boxing, and is a direct mapping to the conditional/ternary/? operator in C/C++/C#/Java/etc

    Even without the new operator, you can get some improvement in VB.Net with this code:

    Public Shared Function IIf(Of T)(ByVal Expression As Boolean, ByVal TruePart As T, ByVal FalsePart As T) As T
        If Expression Then Return TruePart Else Return FalsePart
    End Function
    
    0 讨论(0)
  • 2020-12-20 12:21

    Joel beat me to an answer, but here is a sample program and the generated IL that demonstrates that If() passes through to the IL's underlying ternary operator without boxing.

    Public Class Test
        Public Sub New()
            Dim rnd = New Random()
            Dim result As Integer = If(rnd.Next(1000) < 500, 1, -1)
            Console.WriteLine(result)
        End Sub
    End Class
    

    As you can see the IL has no 'box' statement.

    .method public specialname rtspecialname instance void .ctor() cil managed
    {
        .maxstack 2
        .locals init (
            [0] int32 result,
            [1] class [mscorlib]System.Random rnd)
        L_0000: nop 
        L_0001: ldarg.0 
        L_0002: call instance void [mscorlib]System.Object::.ctor()
        L_0007: nop 
        L_0008: newobj instance void [mscorlib]System.Random::.ctor()
        L_000d: stloc.1 
        L_000e: ldloc.1 
        L_000f: ldc.i4 0x3e8
        L_0014: callvirt instance int32 [mscorlib]System.Random::Next(int32)
        L_0019: ldc.i4 500
        L_001e: blt.s L_0023
        L_0020: ldc.i4.m1 
        L_0021: br.s L_0024
        L_0023: ldc.i4.1 
        L_0024: stloc.0 
        L_0025: ldloc.0 
        L_0026: call void [mscorlib]System.Console::WriteLine(int32)
        L_002b: nop 
        L_002c: nop 
        L_002d: ret 
    }
    

    Given the same program but using the older IIf() function, the following IL is produced. You can see both the boxing, and the function call overhead:

    .method public specialname rtspecialname instance void .ctor() cil managed
    {
        .maxstack 3
        .locals init (
            [0] int32 result,
            [1] class [mscorlib]System.Random rnd)
        L_0000: nop 
        L_0001: ldarg.0 
        L_0002: call instance void [mscorlib]System.Object::.ctor()
        L_0007: nop 
        L_0008: newobj instance void [mscorlib]System.Random::.ctor()
        L_000d: stloc.1 
        L_000e: ldloc.1 
        L_000f: ldc.i4 0x3e8
        L_0014: callvirt instance int32 [mscorlib]System.Random::Next(int32)
        L_0019: ldc.i4 500
        L_001e: clt 
        L_0020: ldc.i4.1 
        L_0021: box int32
        L_0026: ldc.i4.m1 
        L_0027: box int32
        L_002c: call object [Microsoft.VisualBasic]Microsoft.VisualBasic.Interaction::IIf(bool, object, object)
        L_0031: call int32 [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.Conversions::ToInteger(object)
        L_0036: stloc.0 
        L_0037: ldloc.0 
        L_0038: call void [mscorlib]System.Console::WriteLine(int32)
        L_003d: nop 
        L_003e: nop 
        L_003f: ret 
    }
    
    0 讨论(0)
提交回复
热议问题