type - ¿El operador "If" de VB.NET causa el boxeo?
object reference not set to an instance of an object was null c# (2)
Aquellos de nosotros que hemos trabajado en VB / VB.NET hemos visto un código similar a esta abominación:
Dim name As String = IIf(obj Is Nothing, "", obj.Name)
Digo "abominación" por tres simples razones:
-
IIf
es una función , todos cuyos parámetros son evaluados; por lo tanto, siobj
no es nada en la llamada anterior, se lanzará unaNullReferenceException
. Este es un comportamiento inesperado para alguien que está acostumbrado a los operadores ternarios cortocircuitados en lenguajes como C #. - Como
IIf
es una función, incurre en la sobrecarga de una llamada de función. Una vez más, aunque esto no es un gran problema, simplemente no se siente bien para alguien que espera que se comporte como una operación ternaria intrínseca al lenguaje. IIf
no es genérico y, por lo tanto, acepta parámetros de tipoObject
, lo que significa que los siguientes cuadros de llamada (creo) tienen un total de tres enteros:'' boxes 2nd and 3rd arguments as well as return value ''
Dim value As Integer = IIf(condition, 1, -1)
Ahora, en una versión más reciente de VB.NET (no estoy seguro de cuál es el número), se introdujo el operador If
, que funciona exactamente de la misma manera que la función IIf
pero (como lo entiendo) sin los mismos inconvenientes . Es decir, proporciona cortocircuito y es una operación intrínseca de VB. Sin embargo, no estoy seguro de la última parte. La documentación de MSDN no parece indicar si If
encuadra sus argumentos o no. ¿Alguien sabe?
Joel me dio una respuesta, pero aquí hay un programa de ejemplo y el IL generado que demuestra que If () pasa al operador ternario subyacente del IL sin boxear.
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
Como puede ver, el IL no tiene una declaración de ''caja''.
.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
}
Dado el mismo programa pero utilizando la antigua función IIf (), se produce la siguiente IL. Puede ver tanto el boxeo como la sobrecarga de llamadas a funciones:
.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
}
Lo principal es que usted identificó correctamente el nuevo If
como un operador en lugar de una función. También es de tipo seguro y por lo tanto no necesita boxeo, y es un mapeo directo al condicional / ternario /? Operador en C / C ++ / C # / Java / etc
Incluso sin el nuevo operador, puede obtener algunas mejoras en VB.Net con este código:
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