为什么不递增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 2015年

Answers:


124

您正在观察提升操作员的效果。

根据C#5规范的7.3.7节:

提升运算符允许对不可空值类型进行操作的预定义和用户定义运算符也可以与这些类型的可空形式一起使用。提升的运算符由满足特定要求的预定义和用户定义的运算符构造而成,如下所述:

  • 对于一元运算+ ++ - -- ! ~ 符,如果操作数和结果类型均为非空值类型,则存在提升形式的运算符。通过向?操作数和结果类型添加单个修饰符来构造提升形式。如果操作数为null,则提升运算符将产生null值。否则,提升操作符将取消包装操作数,应用基础操作符并包装结果。

因此,基本上,a++在这种情况下,是一个结果为null(作为int?)的表达式,并且该变量保持不变。

您打电话的时候

Console.WriteLine(a);

将其装箱到中object,将其转换为空引用,该引用将打印为空行。


3
有没有一种方法可以不使用而打印“ null” Console.WriteLine(a == null ? "null" : a)
科尔·约翰逊

5
@科尔·约翰逊:Console.WriteLine(a ??“ null”); :)
David Chappelle

2
@DavidChappelle当a为type时int?,我会说a ?? "null"这两个操作数没有通用类型。您需要一个object常见类型的提示。因此,将其中一个操作数转换为该值。在a将被装箱。例如((object)a) ?? "null"a ?? (object)"null"
Jeppe Stig Nielsen

超。您可以链接到规范吗?当我们在自己的类中重载运算符时,我们可以定义它吗?
Phil

@teabaggs:我现在不能轻松地链接,而链接只能是Word文档(您可以通过搜索轻松找到它)。在适当的位置定义运算符重载时,您会自动获得提升的运算符。
乔恩·斯基特

116

乔恩的答案是正确的,但我要补充一些注意事项。

为什么会Console.WriteLine(null)出现编译错误?

共有19个重载,Console.WriteLine其中三个重载适用于a null:一个重载a string,一个重载a char[]和一个重载a object。C#无法确定这三个意思中的哪一个,因此会产生错误。Console.WriteLine((object)null)将是合法的,因为现在很清楚。

为什么Console.WriteLine(a)写空行?

a为null int?。重载分辨率选择object方法的版本,因此将int?装箱为空引用。因此,这基本上与相同Console.WriteLine((object)null),后者写入一个空行。

为什么没有NullReferenceException增量?

您担心的空引用在哪里? a为null int?,不是开头的引用类型!请记住,可为空的值类型是值类型,而不是引用类型,因此,除非将它们装箱成引用类型,否则不要期望它们具有引用语义。另外没有拳击。


0

您要递增null吗???

int? a = null;
a++;

该语句仅表示null++null + 1。

根据本文档,可为空的类型可以表示其基础值类型的正确值范围,以及一个附加的空值。可以为可为空的,发音为“ Int32的Nullable”的值分配从-2147483648到2147483647的任何值,或者可以分配空值

在这里,您要递增null,然后它将变为null值,而不是0或任何其他整数。

为什么打印空白而不是错误?

当您打印具有空值的可为空类型时,它将打印空白而不是错误,因为您正在打印变量,即存储位置的值。可能为null或任何整数。

但是,当您尝试使用来打印null时Console.WriteLine(null),因为null不是变量,因此它不会引用任何内存位置。因此,它给出了错误"NullReferenceException"

然后如何使用Console.WriteLine(2);?? 打印任何整数?

在这种情况下,2将在临时位置进入内存,并且指针指向该内存位置进行打印。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.