Hat der VB.NET „Wenn“ Operator Ursache Boxen?
-
18-09-2019 - |
Frage
Diejenigen von uns, die in VB / VB.NET gearbeitet habe habe Code ähnlich wie diesen Gräuel gesehen:
Dim name As String = IIf(obj Is Nothing, "", obj.Name)
Ich sage "Gräuel" für drei einfache Gründe:
-
IIf
ist eine Funktion , werden alle deren Parameter ausgewertet; also wennobj
nichts in dem obigen Aufruf ist, dann wird einNullReferenceException
geworfen werden. Dies ist ein unerwartetes Verhalten für jemanden, der kurzgeschlossen ternäre Operatoren in Sprachen wie C # gewohnt ist. - Da
IIf
eine Funktion ist, es entsteht somit den Aufwand für einen Funktionsaufruf. Auch wenn dies keine große Sache ist, es funktioniert einfach nicht richtig anfühlen für jemanden, der für sie als ternäre Operation Eigens die Sprache verhalten erwartet. -
IIf
ist nicht generisch und daher akzeptiert Parameter vom TypObject
, das die folgenden Sprechstellen bedeutet (ich glaube) insgesamt drei ganze Zahlen:' boxes 2nd and 3rd arguments as well as return value '
Dim value As Integer = IIf(condition, 1, -1)
Nun, in einigen neueren Version von VB.NET (Ich bin nicht sicher, was die Zahl ist) wurde die If
Operator eingeführt, die genau die gleiche Art und Weise wie die IIf
Funktion funktioniert aber (wie ich es verstehe) ohne die gleichen Mängel auf. Das heißt, es funktioniert bieten Kurzschlüsse und ist ein intrinstic VB Betrieb. Allerdings bin ich über den letzten Teil nicht sicher. Die MSDN-Dokumentation scheint nicht, ob If
Boxen seine Argumente, um anzuzeigen, oder nicht. Kennt jemand?
Lösung
Die Hauptsache ist, dass Sie richtig die neue If
als identifiziert Operator anstatt eine Funktion. Es ist auch typsicher und deshalb nicht Box braucht, und ist eine direkte Zuordnung zu dem bedingten / ternären /? Operator in C / C ++ / C # / Java / etc
Auch ohne den neuen Betreiber, können Sie eine gewisse Verbesserung in VB.Net mit diesem Code erhalten:
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
Andere Tipps
Joel hat mich auf eine Antwort, aber hier ist ein Beispielprogramm und die IL erzeugt, das zeigt, dass, wenn () durch, um den zugrundeliegenden ternären Operator IL ohne Boxen.
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
Wie Sie die IL sehen kann, hat keine 'Box' Aussage.
.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
}
das gleiche Programm gegeben, aber mit der älteren IIf () Funktion wird die folgenden IL hergestellt. Sie können sowohl die Boxen sehen, und den Funktionsaufruf 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
}