为什么GetType返回System.Int32而不是Nullable <Int32>?

Ars*_*yan 29 .net c# reflection nullable gettype

为什么这个代码段的输出System.Int32代替Nullable<Int32>

int? x = 5;
Console.WriteLine(x.GetType());
Run Code Online (Sandbox Code Playgroud)

SLa*_*aks 29

GetType()是一种方法object.
要调用它,Nullable<T>必须将结构框装箱.

你可以在IL代码中看到这个:

//int? x = 5;
IL_0000:  ldloca.s    00 
IL_0002:  ldc.i4.5    
IL_0003:  call        System.Nullable<System.Int32>..ctor

//Console.WriteLine(x.GetType());
IL_0008:  ldloc.0     
IL_0009:  box         System.Nullable<System.Int32>
IL_000E:  callvirt    System.Object.GetType
IL_0013:  call        System.Console.WriteLine
Run Code Online (Sandbox Code Playgroud)

可空类型由CLR专门处理; 不可能有一个可空类型的盒装实例.
相反,装入可空类型将导致空引用(如果HasValue为false)或盒装值(如果有值).

因此,该box System.Nullable<System.Int32>指令产生一个盒装Int32而不是盒装Nullable<Int32>.

因此,这是不可能的GetType(),以以往任何时候都返回Nullable<T>.

要更清楚地看到这一点,请查看以下代码:

static void Main()
{
    int? x = 5;
    PrintType(x);   
}
static void PrintType<T>(T val) {
    Console.WriteLine("Compile-time type: " + typeof(T));
    Console.WriteLine("Run-time type: " + val.GetType());
}
Run Code Online (Sandbox Code Playgroud)

这打印

编译时类型:System.Nullable`1 [System.Int32]
运行时类型:System.Int32


dle*_*lev 8

GetType()不是虚拟的,因此仅在其上定义object.因此,要进行通话,Nullable<Int32>必须先装箱.Nullables有特殊的装箱规则,所以只有Int32值被装箱,这就是报告的类型.