На этот вопрос уже есть ответ:
Что изменилось, применив обнуляемый оператор к типу значения типа, который теперь может хранить нуль.
Как уже говорили другие, "?" - это просто сокращение для изменения на Nullable
. Это просто еще один тип значения с булевым флагом, который говорит, действительно ли существует полезное значение, или это нулевое значение для данного типа. Другими словами, Nullable
выглядит примерно так:
public struct Nullable<T>
{
private readonly bool hasValue;
public bool HasValue { get { return hasValue; } }
private readonly T value;
public T value
{
get
{
if (!hasValue)
{
throw new InvalidOperationException();
}
return value;
}
}
public Nullable(T value)
{
this.value = value;
this.hasValue = true;
}
// Calling new Nullable<int>() or whatever will use the
// implicit initialization which leaves value as default(T)
// and hasValue as false.
}
Очевидно, что в реальном коде есть больше методов (например, GetValueOrDefault()
) и операторов преобразования и т.д. Компилятор C# добавляет операторы lifted, которые эффективно проксируют оригинальные операторы для T
.
Рискуя показаться заезженной пластинкой, скажу, что это все еще тип значения. В нем нет боксирования... и когда вы пишете:
int? x = null;
это не нулевая ссылка - это нулевое значение Nullable
, то есть то, где hasValue
равно false
.
Когда тип nullable является boxed, CLR имеет свойство, при котором значение либо boxed в нулевую ссылку, либо в обычную boxed T. Так что если у вас есть код вроде этого:
int? x = 5;
int y = 5;
object o1 = x;
object o2 = y;
boxed значения, на которые ссылаются o1
и o2
, неотличимы друг от друга. Вы не можете сказать, что одно из них является результатом боксирования нулевого типа.
Синтаксис ?
является синтаксическим сахаром для Nullable
структура.
По сути, когда вы пишете int? myNullableInt
, компилятор изменяет его на Nullable
.
Из MSDN (прокрутите вниз до «Обзор типов, допускающих значение NULL»):
Синтаксис T? это сокращение от Nullable, где T - это тип значения. Эти две формы взаимозаменяемы.
В самом типе значения ничего не меняется, он просто заключен в структуру System.Nullable
.
http://msdn.microsoft.com/en-us/library/b3h38hb0.aspx
Тип меняется с того, каким он был раньше, на тип Nullable.
Если у вас был int, и вы решили сделать его int?:
int myInt;
И вы делаете его:
int? myInt;
теперь это:
Nullable<int> myInt;
В реальности.
В основных терминах, тип nullable - это коробочная версия обычного типа, которая имеет дополнительное булево поле hasValue. Если это поле имеет значение false, то экземпляр является нулевым.
Посмотрите этот ответ, чтобы узнать немного больше подробностей о реализации CLR и почему они выбрали именно ее: Boxing / Unboxing Nullable Types - Why this implementation?