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 просто создает ошибку, позволяя последнему сравнению фактически сравнивать со значением ничего.
Надеюсь, это поможет. По крайней мере, дайте мне