VB.NET の「If」演算子はボックス化を引き起こしますか?
-
18-09-2019 - |
質問
VB/VB.NET で作業したことがある人は、次のような忌まわしいコードに似たコードを見たことがあるでしょう。
Dim name As String = IIf(obj Is Nothing, "", obj.Name)
私が「忌まわしい」と言うのには、次の 3 つの単純な理由があります。
IIf
です 関数, 、すべてのパラメータが評価されます。したがって、もしobj
上記の呼び出しに何もない場合は、NullReferenceException
投げられるだろう。これは、C# などの言語の短絡三項演算子に慣れている人にとっては予期しない動作です。- なぜなら
IIf
は関数であるため、関数呼び出しのオーバーヘッドが発生します。繰り返しますが、これは大したことではありませんが、言語に固有の三項演算として動作することを期待している人にとっては適切ではありません。 IIf
非ジェネリックであるため、次のタイプのパラメータを受け入れます。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
引数をボックス化するかどうか。誰か知っていますか?
解決
主なものは、あなたが正しく、の演算子はのではなく、機能などの新If
を識別していることです。また、タイプセーフであるため、ボクシングを必要としない、との条件付き/値/ 3への直接マッピングのですか?オペレータC IN / C ++ / C#/ Javaのは/ etc
でも、new演算子ずに、あなたはこのコードで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
他のヒント
ジョエルは答えに私を打つが、ここでIfは()ボクシングせずにILの基盤となる三項演算子を通過することを実証しているサンプルプログラムと生成された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はNO '箱' ステートメントを持っていない見ることができるようにます。
.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
}