开发者

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

开发者 https://www.devze.com 2023-03-25 20:54 出处:网络
This question already has answers here: Nullable type is not a nullable type? (4 answers) Closed 8 years ago.
This question already has answers here: Nullable type is not a nullable type? (4 answers) Closed 8 years ago.

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

int? x = 5;
Console.WriteLi开发者_Go百科ne(x.GetType());


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


GetType() isn't virtual, and is thus defined only on object. As such, to make the call, the Nullable<Int32> must first be boxed. Nullables have special boxing rules, though, so only the Int32 value is boxed, and that's the type reported.


You can't box a nullable.

You could do something like this:

public static Type GetCompilerType<T>(this T @object)
{
  return typeof (T);
}

int? x = 5;
Console.WriteLine(x.GetCompilerType());
// prints:
// System.Nullable`1[System.Int32]


Because the type of "5" is int.

If you want to detect if a type is nullable, and the underlying type, use something like this:

public static Type GetActualType(Type type, out bool isNullable)
{
    Type ult = Nullable.GetUnderlyingType(type);
    if (ult != null)
    {
        isNullable = true;
        return ult;
     }
     isNullable = false;
     return type;
}
0

精彩评论

暂无评论...
验证码 换一张
取 消