VB.NET: Boolean из `Nothing`, иногда` false`, иногда Nullreference-Exception - PullRequest
8 голосов
/ 26 января 2011

Исходя из Базовая логическая логика в 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)

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

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

[Option Strict ON]

Ответы [ 5 ]

15 голосов
/ 26 января 2011

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

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

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

4 голосов
/ 26 января 2011

Здесь вы должны понять пару вещей.

first - это то, на что уже указывали другие: 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;

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

2 голосов
/ 26 января 2011

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

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

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

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

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

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

 Dim obj As Object = Nothing  
 b = DirectCast(obj, Boolean) 
1 голос
/ 03 декабря 2013

Я обнаружил, что сравнение булевой переменной со строкой «True», «False» или «Is» ничего не гарантирует, что я получу правильные сравнения.Я использовал функцию для возврата 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 просто создает ошибку, позволяя последнему сравнению фактически сравниваться со значением nothing .

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

1 голос
/ 26 января 2011

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

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

Символ ? означает Nullable(of ).

...