C# 可为null的类型GetType()引发异常

C# 可为null的类型GetType()引发异常,c#,.net,C#,.net,我刚从一位同事那里得到了一个让我发疯的测验。对于这段代码: var x = new Int32?(); string text = x.ToString(); // No exception Console.WriteLine(text); Type type = x.GetType(); // Bang! 为什么第一部分.ToString()工作时不会引发异常,而对GetType()的调用会引发NullReferenceException?ToString是,因此调用时不需要装箱 GetTy

我刚从一位同事那里得到了一个让我发疯的测验。对于这段代码:

var x = new Int32?();
string text = x.ToString(); // No exception
Console.WriteLine(text);
Type type = x.GetType(); // Bang!
为什么第一部分.ToString()工作时不会引发异常,而对GetType()的调用会引发NullReferenceException?

ToString
是,因此调用时不需要装箱

GetType()
不是虚拟方法,因此不是(也不能)重写,因此在调用之前将值装箱。。。装箱一个可空值类型的空值会给出一个空引用

装箱原因见C#4规范第7.5.5节:

如果
M
是引用类型中声明的实例函数成员:

  • 如果
    E
    的类型是值类型,则执行装箱转换(4.3.1)以将
    E
    转换为类型
    对象
    ,并且在以下步骤中将
    E
    视为类型
    对象
    。在这种情况下,
    M
    只能是
    System.Object的成员
请注意,如果您有:

var x = new Int32?(10);
由于装箱,最终的类型与
typeof(int)
相同。使用普通的
GetType()
方法,无法创建值
foo
,从而
foo.GetType()
返回可为空的值类型。(当然,您可以创建一个新的
GetType()
方法,但这是一个次要问题:)


(使用“砰!”意味着上述测验的作者可能是我。如果是这样的话,我很抱歉让你发疯。)

好的。。但是为什么要将最后一行替换为:var boxed=(Int32)x;而是引发InvalidOperationException?这不是装箱,应该引发相同的异常吗?@kabaros:不,这根本不是装箱-
Int32?
Int32
都不是引用类型。这是C#4规范第6.2.3节中描述的显式转换。哦,是的,当然,这非常有意义。谢谢。顺便说一句,这本书很棒,所以你让我们发疯是可以原谅的:)