为什么 n.GetHashCode() 有效,但 n.GetType() 抛出和异常
本文关键字:异常 GetType GetHashCode 有效 为什么 | 更新日期: 2023-09-27 17:48:55
我正在自学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 是空的,这可以解释这一点,但是,为什么在使用 n.GetHashCode() 和 ToString() 时,出于同样的原因我没有收到异常?
谢谢你的帮助,
John。
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
之前有一个constrained
指令/前缀,这本质上意味着"调用虚拟方法时不需要装箱"。从OpCodes.Constrained
文档中:
受约束的前缀旨在允许以统一的方式发出 callvirt 指令,而与 thisType 是值类型还是引用类型无关。
(点击链接了解更多信息。
请注意,可为 null 的值类型的工作方式也意味着即使对于非 null 值,也不会得到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>
类型。