18

VB/VB.NET で作業したことのある私たちは、この忌まわしいコードに似たコードを見てきました。

Dim name As String = IIf(obj Is Nothing, "", obj.Name)

私が「忌み嫌う」と言うのは、次の 3 つの単純な理由からです。

  1. IIfすべてのパラメーターが評価されるfunctionです。したがってobj、上記の呼び出しで が何もない場合は、 aNullReferenceExceptionがスローされます。これは、C# などの言語で短絡三項演算子に慣れている人にとっては予期しない動作です。
  2. は関数であるため IIf、関数呼び出しのオーバーヘッドが発生します。繰り返しますが、これは大したことではありませんが、言語固有の 3 項演算として動作することを期待する人にとっては、正しくないと感じます。
  3. IIfは非ジェネリックであるため、 type のパラメーターを受け入れますObject。つまり、次の呼び出しボックス (私は信じています) は合計 3 つの整数を意味します。

    ' boxes 2nd and 3rd arguments as well as return value '
    Dim value As Integer = IIf(condition, 1, -1)

現在、VB.NET の最近のバージョン (数字が何かはわかりません) では、If演算子が導入されました。これは、関数とまったく同じようにIIf機能しますが、(私が理解しているように) 同じ欠点はありません。つまり、短絡を提供し、本質な VB 操作です。ただし、最後の部分についてはよくわかりません。MSDNのドキュメントにはIf、その引数をボックス化するかどうかが示されていないようです。誰か知っていますか?

4

2 に答える 2

12

主なことは、新しいものを関数ではなく演算子Ifとして正しく識別したことです。また、タイプセーフであるため、ボクシングは必要ありません。また、条件付き/三項/への直接マッピングですか?C / C ++ / C#/ Java/etcの演算子

新しい演算子がなくても、次のコードを使用してVB.Netを改善できます。

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
于 2010-03-09T14:58:01.453 に答える
11

Joel は私に答えてくれましたが、サンプル プログラムと生成された IL は、If() がボクシングなしで IL の基礎となる三項演算子に渡されることを示しています。

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

ご覧のとおり、IL には「ボックス」ステートメントがありません。

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

同じプログラムで古い IIf() 関数を使用すると、次の IL が生成されます。ボクシングと関数呼び出しのオーバーヘッドの両方を確認できます。

.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 
}
于 2010-03-09T15:17:36.297 に答える