Domanda

Quelli di noi che hanno lavorato in VB / VB.NET hanno visto codice simile a questo abominio:

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

dico "abominio" per tre semplici motivi:

  1. IIf è un funzione , i cui parametri vengono valutati; quindi se obj è nulla nella chiamata sopra poi un NullReferenceException sarà gettato. Questo è un comportamento inaspettato per chi è abituato agli operatori ternari in corto circuito in linguaggi come C #.
  2. Poiché IIf è una funzione, essa comporta quindi il sovraccarico di una chiamata di funzione. Ancora una volta, anche se questo non è un grosso problema, semplicemente non si sente giusto a qualcuno che si aspetta per questo comportarsi come un'operazione ternario intrinseca al linguaggio.
  3. IIf non è generica e accetta pertanto parametri di tipo Object, il che significa che le seguenti caselle di chiamata (credo) un totale di tre numeri interi:

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

Ora, in qualche versione più recente di VB.NET (io non sono sicuro di quello che il numero è), l'operatore If è stato introdotto, che funziona esattamente allo stesso modo la funzione IIf ma (se ho capito bene) senza le stesse carenze. Vale a dire, non fornire corto circuito e è un'operazione VB intrinstic. Tuttavia, non sono sicuro circa l'ultima parte. Il MSDN documentazione non sembra indicare se i contenitori di If suoi argomenti o non. Qualcuno sa?

È stato utile?

Soluzione

La cosa principale è che si correttamente identificato il nuovo If come operatore , piuttosto che una funzione. E 'anche typesafe e quindi non ha bisogno di boxe, ed è una mappatura diretto al condizionale / ternario /? operatore in C / C ++ / C # / Java / etc

Anche senza il nuovo operatore, è possibile ottenere qualche miglioramento in VB.Net con questo codice:

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

Altri suggerimenti

Joel mi ha battuto ad una risposta, ma qui è un programma di esempio e il generato IL che dimostra che se () passa attraverso di operatore ternario sottostante del IL, senza la boxe.

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

Come si può vedere la IL non ha alcuna dichiarazione 'scatola'.

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

Dato lo stesso programma ma utilizzando la funzione più vecchio IIf (), la seguente IL viene prodotto. È possibile vedere sia la boxe, e l'overhead chiamata di funzione:

.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 
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top