Я провел некоторые исследования по этому вопросу, используя различные методы для присвоения значений обнуляемому int. Вот что случилось, когда я делал разные вещи. Следует уточнить, что происходит.
Имейте в виду: Nullable<something>
или сокращение something?
- это структура, для которой компилятор, кажется, выполняет большую работу, чтобы позволить нам использовать с нулем, как если бы это был класс.
Как вы увидите ниже, SomeNullable == null
и SomeNullable.HasValue
всегда будут возвращать ожидаемое значение true или false. Хотя это и не показано ниже, SomeNullable == 3
также допустимо (при условии, что SomeNullable - int?
).
В то время как SomeNullable.Value
возвращает нам ошибку времени выполнения, если мы присвоили null
SomeNullable
. Фактически это единственный случай, когда обнуляемые значения могут вызвать у нас проблему благодаря комбинации перегруженных операторов, перегруженного метода object.Equals(obj)
и оптимизации компилятора и обезьяньего бизнеса.
Вот описание некоторого кода, который я запустил, и какой вывод он выдает в метках:
int? val = null;
lbl_Val.Text = val.ToString(); //Produced an empty string.
lbl_ValVal.Text = val.Value.ToString(); //Produced a runtime error. ("Nullable object must have a value.")
lbl_ValEqNull.Text = (val == null).ToString(); //Produced "True" (without the quotes)
lbl_ValNEqNull.Text = (val != null).ToString(); //Produced "False"
lbl_ValHasVal.Text = val.HasValue.ToString(); //Produced "False"
lbl_NValHasVal.Text = (!(val.HasValue)).ToString(); //Produced "True"
lbl_ValValEqNull.Text = (val.Value == null).ToString(); //Produced a runtime error. ("Nullable object must have a value.")
lbl_ValValNEqNull.Text = (val.Value != null).ToString(); //Produced a runtime error. ("Nullable object must have a value.")
Хорошо, давайте попробуем следующий метод инициализации:
int? val = new int?();
lbl_Val.Text = val.ToString(); //Produced an empty string.
lbl_ValVal.Text = val.Value.ToString(); //Produced a runtime error. ("Nullable object must have a value.")
lbl_ValEqNull.Text = (val == null).ToString(); //Produced "True" (without the quotes)
lbl_ValNEqNull.Text = (val != null).ToString(); //Produced "False"
lbl_ValHasVal.Text = val.HasValue.ToString(); //Produced "False"
lbl_NValHasVal.Text = (!(val.HasValue)).ToString(); //Produced "True"
lbl_ValValEqNull.Text = (val.Value == null).ToString(); //Produced a runtime error. ("Nullable object must have a value.")
lbl_ValValNEqNull.Text = (val.Value != null).ToString(); //Produced a runtime error. ("Nullable object must have a value.")
Все так же, как и раньше. Имейте в виду, что инициализация с int? val = new int?(null);
, с нулевым значением, переданным в конструктор, вызвала бы ошибку времени COMPILE, так как VALUE объекта, допускающего обнуляемость, НЕ обнуляется. Только сам объект-оболочка может равняться нулю.
Аналогично, мы получили бы ошибку времени компиляции из:
int? val = new int?();
val.Value = null;
не говоря уже о том, что val.Value
- это свойство только для чтения, то есть мы даже не можем использовать что-то вроде:
val.Value = 3;
но опять же, полиморфные перегруженные операторы неявного преобразования позволят нам сделать:
val = 3;
Не нужно беспокоиться о том, что может случиться, если это работает правильно? :)