Почему троичный оператор в VB.NET принимает Nullable Boolean? - PullRequest
3 голосов
/ 06 октября 2011

Следующие компиляции в VB.NET (с Option Strict On) и выводит False:

Dim b As Boolean? = Nothing
Dim myString = If(b, "True", "False")

Почему это работает?

  • В документации четко указано, что для версии If с тремя аргументами требуется Boolean в качестве первого параметра:

    аргумент1 Обязательно. Boolean. Определяет, какой из других аргументов нужно вычислить и вернуть.

  • и не существует неявного преобразования из Boolean? в Boolean:

    Dim b1 As Boolean? = Nothing
    Dim b2 As Boolean = b1   ' Fails with the following error:
                             '   Option Strict On disallows implicit conversions
                             '   from 'Boolean?' to 'Boolean'.
    

Итак, почему это работает? Это ошибка (или «скрытая возможность») в компиляторе, или это ошибка в документации, и Boolean? на самом деле является допустимым типом для первого аргумента If(a, b, c)?

PS: в C # b ? x : y не не компилируется, если b имеет тип bool?.


РЕДАКТИРОВАТЬ : Я сообщил об этой проблеме в Microsoft Connect . Кто-то из MS ответил и подтвердил, что документация будет обновлена, чтобы включить случай Boolean?.

Ответы [ 4 ]

4 голосов
/ 06 октября 2011

Есть два "почему". Почему это так и почему они так делают. Я могу ответить на первое, второе на Microsoft.

Если вы проверите код, сгенерированный из VB.Net с помощью Reflector, вы увидите следующее:

Dim b As Nullable(Of Boolean) = Nothing
Dim myString As String = IIf(b.GetValueOrDefault, "True", "False")

или C #:

bool? b = null;
string myString = b.GetValueOrDefault() ? "True" : "False";

Таким образом, сам компилятор вставляет GetValueOrDefault для Nullable(of T)

2 голосов
/ 06 октября 2011

Держите ildasm.exe под рукой для подобных вопросов.Компилятор использует Nullable (Of T) .GetValueOrDefault ().Официальная языковая спецификация не запрещает это.И при этом это не освещает иначе, это не необычно.

  IL_0001:  ldloca.s   b
  IL_0003:  initobj    valuetype [mscorlib]System.Nullable`1<bool>
  IL_0009:  ldloca.s   b
  IL_000b:  call       instance !0 valuetype [mscorlib]System.Nullable`1<bool>::GetValueOrDefault()
  IL_0010:  brtrue.s   IL_0019
  etc...
2 голосов
/ 06 октября 2011

Докос утверждает следующее:

Оператор If, который вызывается с тремя аргументами, работает как функция IIf, за исключением того, что он использует оценку короткого замыкания.Функция IIf всегда оценивает все три своих аргумента, тогда как оператор If, имеющий три аргумента, оценивает только два из них.Первый аргумент If оценивается, и результат приводится как логическое значение, True или False.

Он оценивает и затем преобразует.

EDIT1

Интересная часть заключается в том, что во время выполнения приведение не выдает исключение.

0 голосов
/ 06 октября 2011

При работе с nullable вы всегда должны использовать свойство .HasValue, а не просто ссылаться на nullable.VB наследует использование следующего синтаксиса при проверке, был ли создан объект или нет:

If Foo Then
  ' Is instantiated
End If

В результате ваш пример допускает эвакуацию троичного If.Я рекомендую «исправить» ваш код, чтобы быть немного более явным в этом случае:

Dim b As Boolean? = Nothing 
Dim myString = If(b.HasValue, "True", "False") 

В качестве альтернативы, вместо использования троичного If, почему бы просто не переписать его как:

Dim myString = b.GetValueOrDefault(False).ToString()
...