Почему приращение Nullable <int> не вызывает исключения?
Не могли бы вы объяснить, почему Console.WriteLine записывает пустую строку (Console.WriteLine(null)
дать мне ошибку компиляции) и почему нет NullReferenceException (даже a+=1
не должен ее поднимать)?
int? a = null;
a++; // Why there is not NullReferenceException?
Console.WriteLine(a); // Empty line
Ответы
Ответ 1
Вы наблюдаете эффекты снятого оператора.
Из раздела 7.3.7 спецификации С# 5:
Поднятые операторы допускают предопределенные и определяемые пользователем операторы, которые работают с типами значений, не допускающих нулевых значений, которые также могут использоваться с типами NULL для этих типов. Поднятые операторы построены из предопределенных и определяемых пользователем операторов, которые отвечают определенным требованиям, как описано в следующем:
- Для унарных операторов
+ ++ - -- ! ~
существует расширенная форма оператора, если типы операндов и результатов являются неинифицируемыми типами значений. Поднятая форма строится путем добавления единственного модификатора ?
к операнду и типам результатов. Поднятый оператор создает нулевое значение, если операнд равен нулю. В противном случае, снятый оператор разворачивает операнд, применяет основной оператор и завершает результат.
В принципе, a++
в этом случае является выражением с результатом null
(как int?
), и переменная остается нетронутой.
Когда вы вызываете
Console.WriteLine(a);
помещенный в object
, который преобразует его в нулевую ссылку, которая печатается как пустая строка.
Ответ 2
Ответ Jon правильный, но я бы добавил некоторые дополнительные примечания.
Почему Console.WriteLine(null)
дает ошибку компиляции?
Есть 19 перегрузок Console.WriteLine
, и три из них применимы к null
: тот, который принимает string
, тот, который принимает char[]
и тот, который принимает object
. С# не может определить, какой из этих трех вы имеете в виду, поэтому он дает ошибку. Console.WriteLine((object)null)
будет законным, потому что теперь это понятно.
зачем Console.WriteLine(a)
писать пустую строку?
a
- это нуль int?
. Разрешение перегрузки выбирает версию метода object
, поэтому int?
помещается в нулевую ссылку. Так что это в основном то же самое, что Console.WriteLine((object)null)
, который пишет пустую строку.
Почему на приращении нет NullReferenceException
?
Где нулевая ссылка, о которой вы беспокоитесь? a
- это нуль int?
, который не является ссылочным типом для начала! Помните, что типы значений с нулевым значением являются значениями типов, а не ссылочными типами, поэтому не ожидайте, что они будут иметь ссылочную семантику, если они не привязаны к ссылочному типу. В дополнение к боксу нет.
Ответ 3
Увеличиваете ли вы нуль?
int? a = null;
a++;
Этот оператор просто означает null++
i.e. null + 1.
В соответствии с этим документом тип с нулевым значением может представлять правильный диапазон значений для его базового типа значений плюс дополнительное значение null. Nullable, произносится как "Nullable of Int32", может быть присвоено любое значение от -2147483648 до 2147483647, или ему может быть присвоено нулевое значение
Здесь вы увеличиваете значение null, а затем оно становится нулевым значением, а не 0 или любым другим целым числом.
Почему он печатает пустой, а не ошибку?
когда вы печатаете нулевой тип с нулевым значением, он печатает пустой, а не ошибку, потому что вы печатаете переменную i.e значение ячейки памяти. который может быть нулевым или любым целым числом.
Но когда вы пытаетесь напечатать нуль, используя Console.WriteLine(null)
, поскольку значение null не является переменной, поэтому оно не относится к какой-либо ячейке памяти. И, следовательно, он дает ошибку "NullReferenceException"
.
Затем как вы можете напечатать любое целое число с помощью Console.WriteLine(2);
??
В этом случае 2 будет попадать в память во временном местоположении, а указатель указывает на это место памяти для печати.