为什么不尝试添加空值会抛出InvalidOperationException?

时间:2010-01-28 16:47:38

标签: c# .net

int? x = null;
x = x + 1;  // Works, but x remains null

我希望编译器尝试将x转换为int,但显然它不会。

按280Z28编辑:将NullReferenceException更改为InvalidOperationException,这是Nullable<T>.ValueHasValue为假时{{3}}抛出的内容。

7 个答案:

答案 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;
        }