Введите int? против типа int - PullRequest
45 голосов
/ 27 марта 2019

У меня есть это сравнение, которое равно false, как и ожидалось

bool eq = typeof(int?).Equals(typeof(int));

теперь у меня есть этот код

List<object> items = new List<object>() { (int?)123 };
int result = items.OfType<int>().FirstOrDefault();

но это возвращает 123 - в любом случае это значение имеет тип int?

Как это может быть?

Ответы [ 3 ]

59 голосов
/ 27 марта 2019

Обнуляемые типы имеют специальные правила «бокса»;«бокс» - это когда тип значения обрабатывается как object согласно вашему коду.В отличие от обычных типов значений, тип значения, допускающий значение NULL, заключен в квадрат либо как null (обычный null, без типа), либо как тип не обнуляемый (T в T?).Итак: int? помечен как int, а не int?.Затем, когда вы используете OfType<int>() для него, вы получаете все значения, которые int, то есть: единственное значение, которое вы передали, так как оно равно типа int.

9 голосов
/ 27 марта 2019

Обнуляемый тип значения упаковывается в соответствии со следующими правилами

  • Если HasValue возвращает false, создается нулевая ссылка.
  • Если HasValue возвращает true, значение базового типа значения T в штучной упаковке, а не экземпляр обнуляемого значения.

В вашем втором примереПравило соблюдено, поскольку у вас есть значение:

var i = (object)(int?)123;
4 голосов
/ 02 апреля 2019

Немного поздно, но помимо ответа Марка на ваш вопрос, я хочу дать дополнительную информацию о типах значений Nullable в CLR.

CLR имеет встроенную поддержку типов значений, допускающих значение NULL. Эта специальная поддержка предоставляется для бокса, распаковки, вызова GetType, вызова методов интерфейса .

Например, давайте проверим GetType():

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

Как вы думаете, это будет печатать на консоли? System.Nullable<Int32? Нет, результат System.Int32.

Или давайте проверим бокс, который вы отметили в своем вопросе:

Int32? n =5;
Object o = n;
Console.WriteLine("o's type={0}", o.GetType()); // "System.Int32"

Правило таково:

Когда CLR упаковывает экземпляр Nullable, он проверяет, имеет значение null, и если да, то CLR на самом деле ничего не упаковывает, а null вернулся. Если экземпляр Nullable не является нулевым, CLR принимает значение из обнуляемого экземпляра и коробки его. Другими словами, Nullable со значением 5 помещается в штучной упаковке Int32 с значение 5

И, наконец, я хочу объяснить, как CLR добавляет специальную поддержку для вызова методов интерфейса из Nullable Types. Давайте посмотрим на это:

Int32? n = 5;
Int32 result = ((IComparable) n).CompareTo(5); // Compiles & runs OK
Console.WriteLine(result); // 0

В предыдущем коде я приведу Nullable<Int32> к IComparable<Int32> интерфейсу тип. Однако тип Nullable<T> не реализует интерфейс IComparable<Int32> как Int32 делает. Компилятор C # позволяет этот код компилировать в любом случае.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...