什么时候可以为空的类型抛出异常?

时间:2018-05-02 06:32:10

标签: c# .net nullreferenceexception nullable

请考虑以下代码:

int? x = null;
Console.Write ("Hashcode: ");
Console.WriteLine(x.GetHashCode());
Console.Write("Type: ");
Console.WriteLine(x.GetType());

执行时,它会写入Hashcode为0,但在NullReferenceException尝试确定x的类型时失败。 我知道调用可空类型的方法实际上是在底层值上调用的,所以我希望程序在x.GetHashCode()期间失败。

那么,这两种方法之间的根本区别是什么,以及为什么第一种方法失败了呢?

4 个答案:

答案 0 :(得分:34)

这是因为int? x = null;基本上创建了值类型System.Nullable<int>的实例,其中包含&#34;内部&#34; null值(您可以通过.HasVaue属性查看)。当调用GetHashCode时,覆盖Nullable<int>.GetHashCode是候选方法(因为该方法是虚拟的),现在我们有一个Nullable<int>的实例,并执行其实例方法,完美。

调用GetType时,该方法是非虚拟的,因此根据the documentNullable<int>的实例首先被设置为System.Object,并且框值为{ {1}},因此null

答案 1 :(得分:16)

澄清Danny Chen的正确答案:

  • Nullable<T>是值类型。值类型由bool组成,表示nullity(false表示null)和T,值。
  • 与所有其他值类型不同,可空类型不会装箱到装箱Nullable<T>。它们可以装入盒装T或空引用。
  • 实现了由值类型S实现的方法,就好像它有一个不可见的ref S参数一样;这就是this的传递方式。
  • 实现了引用类型C实现的方法,就好像有一个不可见的C参数一样;这就是this的传递方式。
  • 然后有趣的情况是在引用基类中定义的虚方法,并由继承自基类的结构覆盖。

现在你有足够的信息来推断会发生什么。 GetHashCode是虚拟并被Nullable<T> 覆盖,因此当您调用它时,您可以将其称为ref Nullable<T>的不可见this参数。没有拳击发生。

GetType不是虚拟的,因此无法覆盖并在object上定义。因此它期望objectthis,当在Nullable<T>上调用时,必须将接收器装箱,因此可以将其设置为空,因此可以抛出。

如果您致电((object)x).GetHashCode(),那么您会看到异常。

答案 2 :(得分:5)

Nullable<T>.GetHashCode()的实施如下:

public override int GetHashCode()
{
    if (!this.HasValue)
    {
        return 0;
    }
    return this.value.GetHashCode();
}

因此,当值为null时,它将始终为您提供0

x.GetType()null.GetType()相同,后者会抛出Object reference not set to an instance of an object

答案 3 :(得分:1)

似乎GetHashCode有一个空检查。 (使用JetBrains查看defenition)

public override int GetHashCode()
{
  if (!this.hasValue)
    return 0;
  return this.value.GetHashCode();
}