Тип Nullable не является нулевым типом?

Я тестировал несколько типов с нулевым значением, и он не работал так, как я ожидал:

int? testInt = 0; Type nullableType = typeof(int?); Assert.AreEqual(nullableType, testInt.GetType()); // not the same type 

Это тоже не работает:

 DateTime? test = new DateTime(434523452345); Assert.IsTrue(test.GetType() == typeof(Nullable)); //FAIL DateTime? test = new DateTime(434523452345); Assert.IsTrue(test.GetType() == typeof(Nullable)); //STILL FAIL 

Мой вопрос в том, почему testInt.GetType () возвращает int, а typeof (int?) Возвращает истинный тип NULL?

    Согласно MSDN :

    Вызов GetType по типу Nullable приводит к тому, что операция бокса выполняется, когда тип неявно преобразуется в Object. Поэтому GetType всегда возвращает объект Type, который представляет базовый тип, а не тип Nullable.

    Когда вы помещаете объект с нулевым значением, вставляется только базовый тип.

    Опять же, из MSDN :

    В боксе тип нулевых значений с нулевым значением боксирует только тип значения, а не System.Nullable, который обертывает тип значения.

    В дополнение к правильному ответу Ромена, если вы хотите сравнить «реальные» типы (т. Е. Без неявного преобразования любого типа с нулевым типом в его базовый тип), вы можете создать метод расширения следующим образом:

     public static class MyExtensionMethods { public static Type GetRealType(this T source) { return typeof(T); } } 

    И затем попробуйте следующие тесты:

     int? a = 0; Console.WriteLine(a.GetRealType() == typeof(int?)); // True Console.WriteLine(a.GetRealType() == typeof(int)); // False int b = 0; Console.WriteLine(b.GetRealType() == typeof(int)); // True Console.WriteLine(b.GetRealType() == typeof(int?)); // False DateTime? c = DateTime.Now; Console.WriteLine(c.GetRealType() == typeof(DateTime?)); // True Console.WriteLine(c.GetRealType() == typeof(DateTime)); // False DateTime d = DateTime.Now; Console.WriteLine(d.GetRealType() == typeof(DateTime)); // True Console.WriteLine(d.GetRealType() == typeof(DateTime?)); // False 

    РЕДАКТИРОВАТЬ…

    Для полноты – и предложено комментариями SLaks ниже – вот альтернативная версия, которая использует только тип времени компиляции, когда source имеет значение null или Nullable<> ; в противном случае он использует GetType и возвращает тип времени выполнения:

     public static class MyExtensionMethods { public static Type GetRealType(this T source) { Type t = typeof(T); if ((source == null) || (Nullable.GetUnderlyingType(t) != null)) return t; return source.GetType(); } } 

    Хотя C # притворяется, что в хранилищах типа значений хранятся экземпляры типов, происходящих из System.ValueType , которые, в свою очередь, происходят из System.Object , это не так. Каждый тип, полученный из System.ValueType фактически представляет два очень разных типа вещей:

    1. Набор байтов, который (для примитивных типов) представляет данные напрямую, или (для не-примитивных типов структуры) содержит содержимое всех полей, общедоступных и частных, но не содержит информации о типе.
    2. Отдельный объект кучи, который содержит заголовок объекта в дополнение к вышесказанному, тип которого получен из `System.ValueType`.

    Место хранения типа значения удерживает первый; кучи объектов типа значения удерживают второй.

    По разным причинам Microsoft решила, что Nullable должен поддерживать только первое использование. Если вы попытаетесь передать место хранения типа Nullable в код, который ожидает ссылку на объект кучи, система преобразует элемент в T если HasValue является истинным, или просто передайте нулевую ссылку, если HasValue является ложным , Хотя существуют способы создания объекта кучи типа Nullable , обычные методы преобразования хранилища данных типа значения в объект кучи никогда не будут генерировать один.

    Также обратите внимание, что вызов GetType() в хранилище значений не будет фактически определять тип места хранения, а вместо этого преобразует содержимое этого места хранения в объект кучи и затем возвращает тип результирующего объекта. Поскольку места хранения типа Nullable преобразуются либо в экземпляры объектов T либо в нуль, ничто в экземпляре объекта не скажет, было ли место хранения, из которого оно было, Nullable .

    Простой способ проверить, использует ли оператор «is»:

     (i is Nullable) || (i is Nullable) || (i is Nullable) || (i is Nullable) 

    Я понял, что читаю эти две страницы MSDN:

    http://msdn.microsoft.com/en-us/library/ms366789(v=vs.90).aspx

    http://msdn.microsoft.com/en-us/library/ms228597%28v=VS.90%29.aspx

    Ура!

    Давайте будем гением компьютера.