Почему приращение 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 будет попадать в память во временном местоположении, а указатель указывает на это место памяти для печати. ​​