C#编译器是否优化可空类型?

18

有人能解释一下为什么这个单元测试在Visual Studio 2013中失败了吗?

[TestMethod]
public void Inconceivable()
{
    int? x = 0;
    Assert.AreEqual(typeof(int?), x.GetType());
}

Assert.IsInstanceOfType(x,typeof(int?)); - Dan Hunex
你为什么要断言编译器已经静态确定的东西呢?x除了是int?之外,程序不会编译。 - Servy
2
@Servy - 我的观点是单元测试失败了,但它不应该失败。Discosultan非常出色地解释了为什么会这样。我将把GetType是否应该以其目前的方式运行留给哲学家们进行辩论。 - Doug Clutter
@Servy:提出问题。 - Lightness Races in Orbit
@Servy - 这不是一个“真正”的单元测试。我只是为了在这里发布它,以便我的stackoverflow同事可以帮助我理解为什么int?会以那种方式工作而编写的。他们做到了,所以我不认为这是浪费我的时间。希望其他人也能找到这篇文章,并从中受益。这不就是stackoverflow的全部意义吗? - Doug Clutter
显示剩余2条评论
1个回答

27
您的测试失败是因为:

在 Nullable 类型上调用 GetType 会导致执行装箱操作,因为在将类型隐式转换为 Object 时会发生这种情况。因此,GetType 总是返回表示基础类型而不是 Nullable 类型的 Type 对象。

您可以从 如何识别 Nullable 类型 中了解更多信息。

以下是从先前文章中摘取的一些示例:

int? i = 5;
Type t = i.GetType();
Console.WriteLine(t.FullName); //"System.Int32"

请注意:
C# 的 is 运算符也对 Nullable 的基础类型进行操作。因此,您不能使用 is 来确定变量是否为 Nullable 类型。以下示例显示 is 运算符将 Nullable<int> 变量视为 int。
int? i = 5;
if (i is int) { ... } // true   

您的推断是正确的,C#编译器正在优化可空类型。以下是Jon Skeet在《深入C#》中的一段话C# in Depth,它应该可以回答您的问题:
“只有在装箱和拆箱方面,CLR才会对可空类型进行特殊处理。事实上,在.NET 2.0发布前不久,由于社区的请求,行为才发生了改变。”
“Nullable的一个实例被装箱为null引用(如果它没有值)或T的装箱值(如果它有值)。它永远不会装箱成“装箱的可空int”——没有这样的类型。”

在StackOverflow上有一个类似的帖子:可空类型不是可空类型吗?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接