请考虑以下代码:
int? x = null;
Console.Write ("Hashcode: ");
Console.WriteLine(x.GetHashCode());
Console.Write("Type: ");
Console.WriteLine(x.GetType());
执行时,它会写入Hashcode为0
,但在NullReferenceException
尝试确定x
的类型时失败。
我知道调用可空类型的方法实际上是在底层值上调用的,所以我希望程序在x.GetHashCode()
期间失败。
那么,这两种方法之间的根本区别是什么,以及为什么第一种方法失败了呢?
答案 0 :(得分:34)
这是因为int? x = null;
基本上创建了值类型System.Nullable<int>
的实例,其中包含&#34;内部&#34; null
值(您可以通过.HasVaue
属性查看)。当调用GetHashCode
时,覆盖Nullable<int>.GetHashCode
是候选方法(因为该方法是虚拟的),现在我们有一个Nullable<int>
的实例,并执行其实例方法,完美。
调用GetType
时,该方法是非虚拟的,因此根据the document,Nullable<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
上定义。因此它期望object
为this
,当在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();
}