Search code examples
c#.netreflectionnullablegettype

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


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

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

Solution

  • 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