GetHashCode()
是Nullable<T>
覆蓋的虛方法:當它被稱爲一個Nullable<T>
值時,Nullable<T>
執行時,沒有任何拳擊。
GetType()
不是虛方法,這意味着當它的名字,其值將首先盒裝......和拳擊「空」可爲空值的空引用結果 - 因此例外。我們可以從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
文檔:
受約束前綴被設計成允許在獨立的thisType是否是值類型或引用類型以統一的方式進行callvirt指令。
(按照鏈接以獲取更多信息。)
需要注意的是空值類型的裝箱的工作方式也意味着,即使是非空值,你不會得到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>
類型。
檢查了這一點:http://stackoverflow.com/questions/194484/whats-the-strangest-corner-case-youve-seen-in-c-or-net/194671#194671 – mookid8000 2011-04-05 06:01:48
mookid,偉大的線程。謝謝你指出。 – Hex440bx 2011-04-05 06:33:55