Чому приріст Nullable <int> не кидає виняток?


98

Чи можете ви поясніть, чому Console.WriteLine пише порожній рядок ( Console.WriteLine(null)дайте мені помилку компіляції) і чому немає NullReferenceException (навіть a+=1не слід піднімати це)?

int? a = null;
a++; // Why there is not NullReferenceException? 
Console.WriteLine(a); // Empty line

Всі три оператора ++, +=і +підняли варіанти. Тому твердження a++;, a += 1;і a = a + 1;всі вони дозволені. Кожна продукція null(не виняток), якщо aвона спочатку null.
Jeppe Stig Nielsen

5
NullReferenceException? але int?це не так Reference, це лише intте, що може отримати nullцінність
Khaled.K

Відповіді:


124

Ви спостерігаєте за ефектом піднятого оператора .

З розділу 7.3.7 специфікації C # 5:

Підняті оператори дозволяють заздалегідь визначеним та визначеним користувачем операторам, які працюють над типом значення, що не зводиться до нуля, також можна використовувати з нульовими формами цих типів. Підняті оператори будуються з попередньо визначених та визначених користувачем операторів, які відповідають певним вимогам, як описано в наступному:

  • Для одинарних операторів + ++ - -- ! ~ піднята форма оператора існує, якщо операнд і результати результатів є обома типами ненульового значення. Піднята форма побудована шляхом додавання одного ?модифікатора до типів операнду та результатів. Піднятий оператор видає нульове значення, якщо операнд є null. В іншому випадку піднятий оператор розгортає операнд, застосовує базовий оператор і завершує результат.

Отже, a++в даному випадку це вираз із результатом null(якint? ), а змінна залишається недоторканою.

Коли ви телефонуєте

Console.WriteLine(a);

це поле object, яке перетворює його в нульове посилання, яке друкується як порожній рядок.


3
Чи є спосіб надрукувати "null" без використання Console.WriteLine(a == null ? "null" : a)?
Коул Джонсон

5
@Cole Johnson: Console.WriteLine (a "null"); :)
Девід Чаппелль

2
@DavidChappelle Коли aце тип int?, я б сказав, що a ?? "null"не знайде спільного типу для двох операндів. Вам потрібна підказка, яка objectє загальним типом. Тож киньте на це будь-який операнд. aБуде в штучної упаковці. Наприклад ((object)a) ?? "null"або a ?? (object)"null".
Джеппе Стіг Нільсен

супер. Ви можете зв’язатись із специфікацією? чи можемо ми це визначити, коли ми перевантажуємо операторів у власних класах?
Філ

@teabaggs: Я зараз не можу легко зв’язатись, і це посилання буде лише в документі Word (який ви можете знайти досить легко за допомогою пошуку). Ви автоматично отримуєте піднятих операторів, коли визначаєте перевантаження оператора, де це доречно.
Джон Скіт

116

Відповідь Джона правильна, але я б додав кілька додаткових приміток.

Чому виникає Console.WriteLine(null)помилка компіляції?

Є 19 перевантажень, Console.WriteLineі три з них застосовні до null: тієї, яка приймає a string, тієї, яка приймає a, char[]і тієї, яка приймає object. C # не може визначити, який із цих трьох маєте на увазі, тож він дає помилку. Console.WriteLine((object)null)було б законним, бо зараз це зрозуміло.

чому Console.WriteLine(a)пише порожній рядок?

aє нульовим int?. Роздільна здатність перевантаження вибирає objectверсію методу, тому поле int?вказується в нульове посилання. Так що це в основному те саме Console.WriteLine((object)null), що пише порожній рядок.

Чому немає NullReferenceExceptionна прирост?

Де нульова посилання, яка вас хвилює? aце нуль, int?який не є еталонним типом для початку! Пам'ятайте, що типи змінних значень - це типи значень , а не типові типи , тому не сподівайтеся, що вони матимуть посилання-семантику, якщо вони не позначені кодом до опорного типу. Додатку немає боксу.


0

Ти збільшуєш нуль ???

int? a = null;
a++;

Це твердження означає просто null++null + 1.

Згідно з цим документом, тип нульового значення може представляти правильний діапазон значень для його базового типу значення плюс додаткове нульове значення. Nullable, вимовляється "Nullable of Int32", може присвоювати будь-яке значення від -2147483648 до 2147483647, або це може бути призначене нульове значення

Тут ви збільшуєте null, тоді також воно стане нульовим значенням не 0 або будь-яким іншим цілим числом.

Чому він друкує порожнє замість помилки ??

під час друку зведеного типу з нульовим значенням він друкує порожнє замість помилки, оскільки ви друкує змінну, тобто значення місця пам'яті. яка може бути нульовою чи будь-якою цілою.

Але коли ви намагаєтеся надрукувати null за допомогою Console.WriteLine(null), так як null не є змінною, тому вона не стосується жодного місця пам'яті. А значить, це дає помилку "NullReferenceException".

Тоді як можна надрукувати будь-яке ціле число за допомогою Console.WriteLine(2);??

У цьому випадку 2 потрапляє в пам'ять у тимчасовому місці, і вказівник вказує на це місце пам'яті для друку.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.