为什么n.GetHashCode()工作,但n.GetType()抛出和异常? [英] why does n.GetHashCode() work but n.GetType() throws and exception?
问题描述
我自学C#(我不知道很多还没有)。在这个简单的例子:
I am teaching myself C# (I don't know much yet). In this simple example:
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()方法时可能会解释说,但是,为什么不让我得到一个异常出于同样的原因?
Intuitively I understand why the GetType() method would throw an exception. The instance n is null which would explain that but, why don't I get an exception for the same reason when using n.GetHashCode() and ToString() ?
感谢你的帮助,
约翰。
推荐答案
的GetHashCode()
是可空< T>
:当它被称为一个可空< T>
值时,可空< T>
实施时,不任何拳击。
GetHashCode()
is a virtual method overridden in Nullable<T>
: when it's called on a Nullable<T>
value, the Nullable<T>
implementation is used, without any boxing.
的GetType()
的不的虚方法,这意味着当它的名字,其值将首先装箱......和拳击一个空可为空值空引用的结果 - 因此例外。我们可以从IL看到这一点:
GetType()
isn't a virtual method, which means that when it's called, the value is boxed first... and boxing a "null" nullable value results in a null reference - hence the exception. We can see this from the IL:
static void Main()
{
bool? x = null;
Type t = x.GetType();
}
被编译为:
is compiled to:
.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
指令。
The important bit here is L_000a: the box
instruction before the callvirt
instruction at L_000f.
现在比较,与同等代码调用的GetHashCode
:
Now compare that with the equivalent code calling GetHashCode
:
static void Main()
{
bool? x = null;
int hash = x.GetHashCode();
}
编译为:
compiles to:
.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
文件:
This time we have a constrained
instruction/prefix before callvirt
, which essentially means "You don't need to box when you call the virtual method." From the OpCodes.Constrained
documentation:
的约束前缀被设计为允许在独立的是否thisType一种统一的方式来进行callvirt指令是值类型或引用类型。
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.
(点击此链接了解更多信息。)
(Follow the link for more information.)
需要注意的是空值的拳击类型也工作方式意味着,即使一个的非空的价值,你不会得到可空< T>
。例如,考虑:
Note that the way boxing of nullable value types work also means that even for a non-null value, you won't get Nullable<T>
. For example consider:
int? x = 10;
Type t = x.GetType();
Console.WriteLine(t == typeof(int?)); // Prints False
Console.WriteLine(t == typeof(int)); // Prints True
所以你走出类型是的非空的类型有关。到 object.GetType()的调用
将的从不的返回可空< T>
键入
So the type you get out is the non-nullable type involved. A call to object.GetType()
will never return a Nullable<T>
type.
这篇关于为什么n.GetHashCode()工作,但n.GetType()抛出和异常?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!