c#-为什么n.GetHashCode()可以工作,但是n.GetType()会抛出异常?

我正在自学C#(我还不了解).在这个简单的例子中:

bool?          n = null;

Console.WriteLine("n               = {0}", n);
Console.WriteLine("n.ToString()    = {0}", n.ToString());
Console.WriteLine("n.GetHashCode() = {0}", n.GetHashCode());

// this next statement causes a run time exception

Console.WriteLine("n.GetType()     = {0}", n.GetType());

凭直觉我理解为什么GetType()方法会引发异常.实例n为null,这可以解释这一点,但是,为什么在使用n.GetHashCode()和ToString()时出于相同的原因却没有得到异常?

谢谢您的帮助,

约翰.

最佳答案
GetHashCode()是在Nullable< T>中重写的虚拟方法:在Nullable< T>中调用值,Nullable< T>使用实现,无需任何装箱.

GetType()不是虚拟方法,这意味着在调用它时,该值会先装箱…然后将“ null”可空值装箱会导致空引用-因此是异常.我们可以从IL中看到这一点:

static void Main()
{
    bool? x = null;
    Type t = x.GetType();
}

编译为:

.method private hidebysig static void Main() cil managed
{
    .entrypoint
    .maxstack 1
    .locals init (
        [0] valuetype [mscorlib]System.Nullable`1<bool> nullable,
        [1] class [mscorlib]System.Type 'type')
    L_0000: nop 
    L_0001: ldloca.s nullable
    L_0003: initobj [mscorlib]System.Nullable`1<bool>
    L_0009: ldloc.0 
    L_000a: box [mscorlib]System.Nullable`1<bool>
    L_000f: callvirt instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()
    L_0014: stloc.1 
    L_0015: ret 
}

这里重要的一点是L_000a:在L_000f的callvirt指令之前的box指令.

现在将其与调用GetHashCode的等效代码进行比较:

static void Main()
{
    bool? x = null;
    int hash = x.GetHashCode();
}

编译为:

.method private hidebysig static void Main() cil managed
{
    .entrypoint
    .maxstack 1
    .locals init (
        [0] valuetype [mscorlib]System.Nullable`1<bool> nullable,
        [1] int32 num)
    L_0000: nop 
    L_0001: ldloca.s nullable
    L_0003: initobj [mscorlib]System.Nullable`1<bool>
    L_0009: ldloca.s nullable
    L_000b: constrained [mscorlib]System.Nullable`1<bool>
    L_0011: callvirt instance int32 [mscorlib]System.Object::GetHashCode()
    L_0016: stloc.1 
    L_0017: ret 
}

这次,我们在callvirt之前有一个受约束的指令/前缀,这实际上意味着“调用虚拟方法时不需要装箱”.从OpCodes.Constrained文档中:

The constrained prefix is designed to allow callvirt instructions to be made in a uniform way independent of whether thisType is a value type or a reference type.

(单击链接以获取更多信息.)

注意,可空值类型装箱的方式还意味着即使对于非空值,您也不会得到Nullable< T>.例如考虑:

int? x = 10;
Type t = x.GetType();
Console.WriteLine(t == typeof(int?)); // Prints False
Console.WriteLine(t == typeof(int)); // Prints True

因此,得出的类型是涉及的非空类型.调用object.GetType()将永远不会返回Nullable< T>.类型.

转载注明原文:c#-为什么n.GetHashCode()可以工作,但是n.GetType()会抛出异常? - 代码日志