Pregunta

Los que han trabajado en VB / VB.NET han visto un código similar a esta abominación:

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

Yo digo "abominación" por tres razones simples:

  1. IIf es un función , cuyos parámetros son evaluados; por lo tanto, si obj hay nada en la llamada anterior a continuación, un NullReferenceException será lanzada. Este es un comportamiento inesperado para alguien que está acostumbrado a los operadores ternarios en cortocircuito en lenguajes como C #.
  2. Debido IIf es una función, por tanto, 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 para que se comporte como una operación ternaria intrínseca al lenguaje.
  3. IIf no es genérico y por lo tanto acepta parámetros de tipo Object, lo que significa las siguientes cajas de llamada (creo) un total de tres números enteros:

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

Ahora, en alguna versión más reciente de VB.NET (no estoy seguro de lo que es el número), se introdujo el operador If, que funciona exactamente de la misma manera que la función IIf pero (como yo lo entiendo) y sin las mismas deficiencias. Es decir, que hace proporcionar cortocircuitos y es una operación VB intrinstic. Sin embargo, no estoy seguro acerca de la última parte. No parece que la MSDN la documentación para indicar si las cajas If sus argumentos o no. ¿Alguien sabe?

¿Fue útil?

Solución

Lo más importante es que ha identificado correctamente el nuevo If como un operador en lugar de una función. También es typesafe y por lo tanto no necesita el boxeo, y es una asignación directa a la condicional / ternaria /? operador en C / C ++ / C # / Java / etc

Incluso sin el nuevo operador, se puede conseguir una cierta mejora 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

Otros consejos

Joel me adelantó una respuesta, pero aquí es un ejemplo de programa y el IL generado que demuestra que Si () pasa a través de operador ternario subyacente de la IL sin el boxeo.

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 se puede ver la IL tiene ninguna declaración '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 función de más edad IIf (), el siguiente IL se produce. Se puede ver tanto en el boxeo, y la sobrecarga de llamada de función:

.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 
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top