Question

Ceux d'entre nous qui ont travaillé dans VB / VB.NET ont vu un code similaire à cette abomination:

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

Je dis "abomination" pour trois raisons simples:

  1. IIf est une fonction , dont tous les paramètres sont évalués; Par conséquent, si obj est rien dans l'appel ci-dessus un NullReferenceException sera jeté. Ce comportement est inattendu pour quelqu'un qui est habitué aux opérateurs ternaires court-circuité dans des langues comme C #.
  2. Comme IIf est une fonction, il engage donc la surcharge d'un appel de fonction. Encore une fois, bien que ce n'est pas une grosse affaire, ça ne se sent pas bien à quelqu'un qui attend pour se comporter comme une opération ternaire intrinsèque à la langue.
  3. IIf est non générique et accepte donc les paramètres de type Object, ce qui signifie que les boîtes d'appel suivantes (je crois) un total de trois entiers:

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

Maintenant, dans une version plus récente de VB.NET (je ne suis pas sûr de ce que le nombre est), l'opérateur de If a été introduit, qui fonctionne exactement de la même manière que la fonction IIf mais (si je comprends bien) sans les mêmes défauts. C'est-à-dire, il fait fournir un court-circuit et est une opération intrinstic VB. Cependant, je ne suis pas sûr de la dernière partie. documentation MSDN ne semble pas indiquer si les boîtes de If ses arguments ou ne pas. Est-ce que quelqu'un sait?

Était-ce utile?

La solution

La chose principale est que vous avez identifié correctement la nouvelle If comme opérateur plutôt qu'une fonction. Il est également typesafe et n'a donc pas besoin de la boxe, et est une application directe au conditionnel / ternaire /? opérateur en C / C ++ / C # / Java / etc

Même sans le nouvel opérateur, vous pouvez obtenir une certaine amélioration dans VB.Net avec ce code:

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

Autres conseils

Joel m'a battu à une réponse, mais voici un exemple de programme et généré IL qui démontre que si () passe à travers l'opérateur ternaire sous-jacente de l'IL sans 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

Comme vous pouvez le voir l'IL n'a pas de déclaration « boîte ».

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

Étant donné le même programme, mais en utilisant la fonction IIf () plus, l'IL est produit suivant. Vous pouvez voir à la fois la boxe, et l'appel de fonction au-dessus:

.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 
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top