Why GetType returns System.Int32 instead of Nullable<Int32>?

Arsen Mkrtchyan picture Arsen Mkrtchyan · Aug 3, 2011 · Viewed 7.1k times · Source

Why is the output of this snippet System.Int32 instead of Nullable<Int32>?

int? x = 5;
Console.WriteLine(x.GetType());

Answer

SLaks picture SLaks · Aug 3, 2011

GetType() is a method of object.
To call it, the Nullable<T> struct must be boxed.

You can see this in the IL code:

//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

Nullable types are treated specially by CLR; it is impossible to have a boxed instance of a nullable type.
Instead, boxing a nullable type will result in a null reference (if HasValue is false), or the boxed value (if there is a value).

Therefore, the box System.Nullable<System.Int32> instruction results in a boxed Int32, not a boxed Nullable<Int32>.

Therefore, it is impossible for GetType() to ever return Nullable<T>.

To see this more clearly, look at the following code:

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());
}

This prints

Compile-time type: System.Nullable`1[System.Int32]
Run-time type: System.Int32