int? x = null;
x = x + 1; // Works, but x remains null
我希望编译器尝试将x转换为int,但显然它不会。
按280Z28编辑:将NullReferenceException
更改为InvalidOperationException
,这是Nullable<T>.Value
在HasValue
为假时{{3}}抛出的内容。
答案 0 :(得分:10)
这是根据提升的二元运算符的规范。从§7.2.7开始:
对于二元运算符
+ - * / % & | ^ << >>
如果操作数和结果类型都是非可空值类型,则存在提升形式的运算符。通过向每个操作数和结果类型添加单个
?
修饰符来构造提升形式。 如果一个或两个操作数为空,则提升的运算符产生空值(bool?类型的&amp;和|运算符除外,如第7.10.3节所述)。否则,提升的运算符解包操作数,应用基础运算符,并包装结果。
理由是这样的:你可以将null
视为可以为空的类型,意思是“我不知道它的价值是什么。” “我不知道”加一个的结果是什么? “我不知道。”因此,结果应为null
。
答案 1 :(得分:5)
Nullables实际上从来就不是空引用。它们始终是对象引用。他们的内部类覆盖了==
和=
运算符。如果将它们与null进行比较,它们将返回HasValue
属性的值。
答案 2 :(得分:2)
当你将它声明为Nullable时,为什么期望编译器将其强制转换为int?编译器正在执行您已经告诉它的操作并且null +1 = null。
在尝试添加int之前,您必须显式转换或检查x.HasValue。
答案 3 :(得分:2)
这样做的原因是编译器为可空类型创建了一个“提升”运算符 - 在这种情况下它类似于:
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
答案 4 :(得分:0)
不幸的是,它没有。 x = X + 1中的 X 在第一行中为空,因此您将1添加为null,等于null。
因为它是一个可以为空的int,你可以使用x.HasValue来检查它是否有值,然后使用x.Value来获取实际的int值
答案 5 :(得分:0)
无论x
实际上是否永远为空,这都不是重点。
重点是,您何时在尝试执行添加时看到过NullReferenceException
?
以下示例也不会抛出NullReferenceException
并且完全有效。
string hello = null;
string world = "world";
string hw = hello+world;
如果您尝试访问空对象上的成员,则只能获得NullReferenceException
。
答案 6 :(得分:-1)
INT?永远不能为null,因为它是一个结构。结构存在于堆栈中,堆栈不能很好地处理null。
请参阅What is a NullPointerException, and how do I fix it?
此外,可空类型有2个非常有用的属性:HasValue,Value
此代码:
if (x != null)
{
return (int) x;
}
应该重构:
if (x.HasValue)
{
return x.Value;
}