Подтвердить что ты не робот

Почему GetType возвращает System.Int32 вместо Nullable <Int32>?

Почему вывод этого фрагмента System.Int32 вместо Nullable<Int32>?

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

Ответ 1

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

Неверные типы обрабатываются специально 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());
}

Отпечатает

Тип времени компиляции: System.Nullable`1 [System.Int32]
Тип времени выполнения: System.Int32

Ответ 2

GetType() не является виртуальным и определяется, таким образом, только на object. Таким образом, чтобы сделать вызов, Nullable<Int32> должен быть в коробке. Однако у Nullables есть специальные правила бокса, поэтому в коробке помещается только значение Int32 и что указанный тип.

Ответ 3

Вы не можете box с нулевым значением.

Вы можете сделать что-то вроде этого:

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

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

Ответ 4

Поскольку тип "5" является int.

Если вы хотите определить, является ли тип нулевым и базовый тип, используйте что-то вроде этого:

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