Pergunta

Aqueles de nós que já trabalhou em VB / VB.NET ter visto um código semelhante a essa abominação:

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

Eu digo "abominação" por três razões simples:

  1. IIf é um Função , cujos parâmetros são avaliados; portanto, se obj há nada na chamada acima, em seguida, um NullReferenceException será lançada. Este é um comportamento inesperado para alguém que está acostumado a operadores ternários curto-circuito em linguagens como C #.
  2. Porque IIf é uma função, que incorre, assim, a sobrecarga de uma chamada de função. Mais uma vez, embora este não é um grande negócio, ele simplesmente não se sente bem para alguém que espera por ele para se comportar como uma intrínseca operação ternária à linguagem.
  3. IIf é não-genérico e, portanto, aceita parâmetros do tipo Object, o que significa que as seguintes caixas de chamada (creio eu) um total de três inteiros:

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

Agora, de alguma versão mais recente VB.NET (não tenho certeza qual é o número), o operador If foi introduzido, que funciona exatamente da mesma forma que a função IIf mas (como eu o entendo) sem as mesmas deficiências. Ou seja, ele não fornecer um curto-circuito e é uma operação VB intrinstic. No entanto, eu não tenho certeza sobre a última parte. A MSDN documentação não parece indicar se caixas If seus argumentos ou não. Alguém sabe?

Foi útil?

Solução

A principal coisa é que você identificou corretamente o novo If como um operador , em vez de uma função. Também é typesafe e, portanto, não precisa de boxe, e é um mapeamento direto para a condicional / ternário /? operador em C / C ++ / C # / Java / etc

Mesmo sem o novo operador, você pode obter alguma melhora em VB.Net com 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

Outras dicas

Joel bater-me a uma resposta, mas aqui é um programa de exemplo ea IL gerado que demonstra que, se () passa através de operador ternário subjacente da IL sem 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

Como você pode ver a IL tem nenhuma declaração 'caixa'.

.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 o mesmo programa, mas usando a função mais velho IIf (), a seguinte IL é produzido. Você pode ver tanto o boxe, e a sobrecarga chamada de função:

.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 em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top