VB.NET: Boolean из `Nothing`, иногда`false`, иногда Nullreference-Exception

Исходя из базовой логической логики в C#, мне было интересно, почему:

Dim b As Boolean
Dim obj As Object = Nothing
'followig evaluates to False'
b = DirectCast(Nothing, Boolean)
'This throws an "Object reference not set to an instance of an object"-Exception'
b = DirectCast(obj, Boolean)

CType(obj, Boolean) оценил бы False(как только CBool(obj)), Я думаю, это потому, что компилятор использует вспомогательную функцию, но это не моя тема.

Почему кастинг Nothing в Boolean оценивает Falseв то время как приведение объекта, который является Nothing в Boolean бросает Nullreference-Exception? Имеет ли это смысл?

[Option Strict ON]

5 ответов

Решение

Предположительно, это потому, что Nothingв VB.NET это не совсем то же самое, чтоnullв C#.

В случае типов значенийNothingподразумеваетзначение по умолчанию этого типа. В случае Booleanзначение по умолчанию FalseТаким образом, актерский состав успешен.

Одно из основных различий между типами значений, такими как Integer или структурами, и ссылочными типами, такими как Form или String, заключается в том, что ссылочные типы поддерживают нулевое значение. То есть переменная ссылочного типа может содержать значение Nothing, что означает, что переменная на самом деле не ссылается на значение. Напротив, переменная типа value всегда содержит значение. Целочисленная переменная всегда содержит число, даже если это число равно нулю. Если вы присваиваете значение Nothing переменной типа значения, переменной типа значения просто присваивается значение по умолчанию (в случае Integer это значение по умолчанию равно нулю). В текущем CLR нет способа взглянуть на переменную Integer и определить, не было ли ей присвоено значение - тот факт, что она содержит ноль, не обязательно означает, что ей не было присвоено значение.
- Правда о Nullable Типах и VB...

РЕДАКТИРОВАТЬ: Для дальнейшего выяснения, причина, по которой второй пример бросает NullReferenceException во время выполнения, потому что CLR пытается распаковать Object (ссылочный тип) к Boolean, Конечно, это не получается, потому что объект был инициализирован с нулевой ссылкой (установив его равным Nothing):

Dim obj As Object = Nothing

Помните, что, как я объяснил выше, ключевое слово VB.NET Nothing по-прежнему работает так же, как null в C#, когда дело доходит до ссылочных типов. Это объясняет, почему вы получаете NullReferenceException потому что объект, который вы пытаетесь разыграть, является буквально нулевой ссылкой. Он вообще не содержит значения и поэтому не может быть распакован в Boolean тип.

Вы не видите того же поведения, когда пытаетесь привести ключевое слово Nothing в булево, то есть:

Dim b As Boolean = DirectCast(Nothing, Boolean)

потому что ключевое слово Nothing (на этот раз в случае типов значений) просто означает "значение по умолчанию этого типа". В случае Boolean, это FalseТаким образом, актерский состав является логичным и простым.

Есть пара вещей, которые вы должны осознать здесь.

Первый - это то, что уже указали другие: Nothing может быть интерпретирован компилятором VB как просто Boolean значение False учитывая надлежащий контекст, такой как Dim b As Boolean = Nothing,

Это означает, что когда компилятор видит это:

b = DirectCast(Nothing, Boolean)

Видит буквальный (Nothing) и также видит, что вы хотите использовать этот литерал как Boolean, Это делает это легким делом.

Но теперь вот вторая вещь, которую вы должны осознать. DirectCast на Object по сути, операция распаковки (для типов значений). Итак, что должно произойти с точки зрения компилятора VB: должно быть Boolean в этом поле, иначе операция не удастся. Поскольку на самом деле в коробке ничего нет - и на этот раз мы действительно ничего не говорим, как в null- это исключение.

Если бы я перевел этот код на C#, он бы выглядел так:

bool b;
object obj = null;

b = (bool)default(bool);

b = (bool)obj;

Надеюсь, это немного прояснит ситуацию?

Есть разница между использованием ключевого слова (литерал) Nothing и использование ссылочной переменной, значение которой равно Nothing,

  • В VB.NET литерал (ключевое слово) Nothing получает специальное лечение. Nothing Ключевое слово может быть автоматически преобразовано в тип значения, используя значение по умолчанию этого типа.

  • Ссылочная переменная, значение которой равно Nothing это отличается. Вы не получаете особого поведения.

  • В документации говорится, что DirectCast "требует наследования или реализации отношений между типами данных двух аргументов".

  • очевидно Object не наследует и не реализует Boolean, если вы не положили в штучной упаковке Boolean в переменную объекта.

Поэтому приведенный ниже код завершается с ошибкой во время выполнения за исключением.

 Dim obj As Object = Nothing  
 b = DirectCast(obj, Boolean) 

Чтобы получить ожидаемое поведение, вам нужен этот код:

Dim b As Boolean?
Dim obj As Object = Nothing  
b = DirectCast(obj, Boolean?) 

Характер ? имею в виду Nullable(of ),

Я обнаружил, что сравнение булевой переменной со строкой "Истина", "Ложь" или "Ничего", кажется, ничего не гарантирует, что я получаю правильные сравнения. Я использовал функцию для возврата html-строки div с изображением переключателя, отмеченного или не отмеченного переключателем, и у меня возникла проблема, когда ничего не возвращалось как ложное. Использование строки variable = "True" или "False" и выполнение последней проверки с помощью IS NOTHING помогли решить эту проблему.

Dim b as boolean = nothing

response.write CheckValue(b = "True")
response.write (b = "False")
response.write (b is nothing)

Function CheckValue(inVal as boolean) as string
  if inVal then 
    return ("<div><img src="checked.png" ></div>
  else
    return ("<div><img src="unchecked.png" ></div>    
  end if
end function

Система, по-видимому, выполняет преобразование в строку при неявном сравнении со строкой, тогда как использование метода .tostring просто создает ошибку, позволяя последнему сравнению фактически сравнивать со значением ничего.

Надеюсь, это поможет. По крайней мере, дайте мне

Другие вопросы по тегам