Вопрос

Те из нас, кто работал в VB / VB.NET, видели код, похожий на эту мерзость:

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

Я говорю "мерзость" по трем простым причинам:

  1. IIf является функция, все параметры которого оцениваются;следовательно, если obj ничего ли в приведенном выше вызове, тогда a NullReferenceException будет выброшен.Это неожиданное поведение для тех, кто привык к короткозамкнутым троичным операторам в таких языках, как C #.
  2. Потому что IIf является функцией, таким образом, она несет накладные расходы на вызов функции.Опять же, хотя в этом нет ничего особенного, это просто кажется неправильным тому, кто ожидает, что это будет вести себя как троичная операция, присущая языку.
  3. IIf не является универсальным и, следовательно, принимает параметры типа Object, что означает , что следующие поля вызова (я полагаю) содержат в общей сложности три целых числа:

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

Теперь, в какой-то более поздней версии VB.NET (я не уверен, что это за номер), If был введен оператор, который работает точно так же, как IIf функциональный, но (как я понимаю) без тех же недостатков.То есть, это делает обеспечить короткое замыкание, и это является внутренняя операция VB.Однако я не уверен насчет последней части.В Документация MSDN похоже, это не указывает на то, является ли If приводит свои аргументы или нет.Кто-нибудь знает?

Это было полезно?

Решение

Главное, чтобы вы правильно определили новый If в качестве оператор скорее, чем функция.Он также безопасен для типов и, следовательно, не нуждается в боксировании и представляет собой прямое сопоставление с условным / троичным /?оператор в C / C ++ / C # / Java / etc

Даже без нового оператора вы можете добиться некоторого улучшения в VB.Net с помощью этого кода:

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

Другие советы

Джоэл опередил меня с ответом, но вот пример программы и сгенерированный IL, который демонстрирует, что If() переходит к базовому троичному оператору IL без боксирования.

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

Как вы можете видеть, в IL нет оператора 'box'.

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

При использовании той же программы, но с использованием более старой функции IIf() создается следующий IL.Вы можете видеть как бокс, так и накладные расходы на вызов функции:

.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 
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top