Я провел некоторое исследование по этому вопросу, используя различные методы для присвоения значений обнуляемому int. Вот что случилось, когда я делал разные вещи. Следует уточнить, что происходит. Имейте в виду: Nullable<something>
или сокращение something?
- это структура, для которой компилятор, кажется, проделывает большую работу, чтобы позволить нам использовать с нулем, как если бы это был класс.
Как вы увидите ниже, SomeNullable == null
и SomeNullable.HasValue
всегда будет возвращать ожидаемый истинным или ложным. Хотя это и не показано ниже, 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 объекта, допускающего значение NULL, НЕ может иметь значение NULL. Только сам объект-оболочка может равняться нулю.
Аналогично, мы получили бы ошибку времени компиляции из:
int? val = new int?();
val.Value = null;
не говоря уже о том, что val.Value
это свойство только для чтения, то есть мы не можем даже использовать что-то вроде:
val.Value = 3;
но опять же, полиморфные перегруженные операторы неявного преобразования позволят нам сделать:
val = 3;
Не нужно беспокоиться о том, что может случиться, если это работает правильно? :)