int? x = null;
x = x + 1; // Works, but x remains null
我期望编译器会尝试将x转换为int,但显然它没有这样做。
由280Z28编辑:将
NullReferenceException
更改为InvalidOperationException
,因为这是Nullable<T>.Value
在HasValue
为false时抛出的异常。int? x = null;
x = x + 1; // Works, but x remains null
NullReferenceException
更改为InvalidOperationException
,因为这是Nullable<T>.Value
在HasValue
为false时抛出的异常。这符合提升的二元运算符规范。根据 §7.2.7:
对于二元运算符
+ - * / % & | ^ << >>
如果操作数和结果类型都是非空值类型,则该运算符存在升级形式。升级形式是通过为每个操作数和结果类型添加一个
?
修饰符来构造的。如果一个或两个操作数为 null,则提升的运算符将产生 null 值(bool? 类型的 & 和 | 运算符是例外,在 §7.10.3 中有描述)。否则,提升的运算符将解开操作数,应用底层运算符,然后包装结果。
理由是:你应该将可空类型的 null
视为“我不知道该值是什么”。 “我不知道” 加一 的结果是什么?“我不知道”。因此,结果应为 null
。
可空类型实际上永远不会是 null 引用。它们始终是对象引用。它们的内部类重写了 ==
和 =
运算符。如果它们与 null 进行比较,它们将返回 HasValue
属性的值。
public static int? operator +(int? a, int? b)
{
return (a == null || b == null) ? (int?)null : a.Value + b.Value
}
我认为,如果您尝试将结果分配给非空值,编译器将被迫使用非空重载并将x转换为int。
e.g. int i = x + 1; //throws runtime exception
既然你已经将它声明为可空类型,为什么希望编译器将其转换为int类型呢?编译器正在执行你告诉它要做的事情,null + 1 = null。
在尝试添加int之前,您必须显式地进行转换或检查x.HasValue。
很遗憾,它并没有。在x = X + 1中的X与第一行中的null相同,因此您正在将1添加到null,其结果为null。
由于它是可空int,您可以使用x.HasValue来检查它是否具有值,然后使用x.Value获取实际的int值。
x
是否为null,这并不是关键。NullReferenceException
?NullReferenceException
,而且是完全有效的。string hello = null;
string world = "world";
string hw = hello+world;
只有在尝试访问一个空对象的成员时,才会出现NullReferenceException
。
int?类型永远不可能是null,因为它是一个结构体。结构体存储在栈上,而栈不能很好地处理null。
请参见什么是NullPointerException,我该如何修复它?
另外,可空类型有2个非常有用的属性:HasValue和Value
这段代码:
if (x != null)
{
return (int) x;
}
应该重构为:
if (x.HasValue)
{
return x.Value;
}