Почему может int?установить в null есть свойства экземпляра? - PullRequest
7 голосов
/ 21 декабря 2011

Мне интересно, почему работает следующий код (запускается под отладчиком VS):

int? x = null;
null
x.HasValue
false

Если x действительно равно нулю, к какому экземпляру относится HasValue? HasValue реализован как метод расширения, или это особый случай компилятора, чтобы он волшебным образом работал?

Ответы [ 9 ]

9 голосов
/ 21 декабря 2011

Потому что x не является ссылочным типом. ? - это просто синтаксический сахар для Nullable<T>, то есть struct (тип значения).

5 голосов
/ 21 декабря 2011

int? на самом деле является структурой Nullable<int>. Следовательно, ваш x не может быть нулевым, поскольку он всегда является экземпляром структуры.

4 голосов
/ 21 декабря 2011

Ответ, махающий рукой: обнуляемые структуры - это магия.

Более длинный ответ: Null на самом деле не то, что представлено значением.Когда вы присваиваете null для nullable структуры, то, что вы увидите, происходит за кулисами иначе.

int? val = null; // what you wrote 
Nullable<Int32> val = new Nullable<Int32>(); // what is actually there

В этом случае создается экземпляр структуры, для которого T Value установлено по умолчаниюзначение и для свойства bool HasValue установлено значение false.

Единственный раз, когда вы на самом деле получите нулевую ссылку из Nullable<T>, это когда она упакована, как поля Nullable<T>непосредственно к T или нулю, в зависимости от того, установлено ли значение.

2 голосов
/ 21 декабря 2011

Есть несколько значений для null.

Один из языков программирования, который представляет переменные и память на основе указателей (который включает ссылки на C #, хотя он скрывает некоторые детали), - это «ни на что не указывает».

Другое - «это не имеет никакого значимого значения».

В ссылочных типах мы часто используем первые для представления последних. Мы могли бы использовать string label = null для обозначения «нет значащего ярлыка». Однако остается, что он все еще также - вопрос того, что происходит с точки зрения того, что находится в памяти и что указывает на это. Тем не менее, это довольно чертовски полезно, какой позор, мы не могли сделать это с int и DateTime в C # 1.1

Это то, что предоставляет Nullable<T>, средство, чтобы сказать "нет значащего значения", но на уровне ниже это не null таким же образом, как строка null (если не заключено в коробку). Ей присвоено значение NULL и равно NULL, поэтому он логически равен NULL и NULL в соответствии с какой-либо другой семантикой, но он не равен NULL в разнице реализации «не указывает ни на что» между ссылочными типами и типами значений.

Только аспект "ничто не указывает" на ссылочный тип null не позволяет вам вызывать методы экземпляра для него.

И на самом деле, даже это не совсем верно. IL, давайте будем вызывать методы экземпляра по нулевой ссылке, и пока он не взаимодействует с какими-либо полями, он будет работать. Он не может работать, если ему нужны (прямо или косвенно) эти поля, поскольку они не существуют по нулевой ссылке, но он может вызвать null.FineWithNull(), если этот метод был определен как:

int FineWithNull()
{
  //note that we don't actually do anything relating to the state of this object.
  return 43;
}

С C # было решено запретить это, но это не правило для всех .NET (я думаю, что F # позволяет это, но я не уверен, я знаю, что неуправляемый C ++ позволял это, и это было полезно в некоторых очень редких случаях ).

1 голос
/ 21 декабря 2011

Это совершенно новый тип. Nullable это не T.

То, что у вас есть, является универсальным классом примерно так:

public struct Nullable<T> 
{
    public bool HasValue { get { return Value != null; } }
    public T Value { get; set; }
}

Я уверен, что это еще не все (особенно в геттере и сеттере, но это в двух словах.

1 голос
/ 21 декабря 2011

Nullable не на самом деле ссылочный тип, и его методы экземпляра являются одним из мест, где это проявляется. По сути, это структурный тип, содержащий логический флаг и значение типа, из которого он может иметь значение null. Языковые специальные операторы для различных случаев [для подъема или в некоторых случаях для рассмотрения (bool?) Null false) и литерала null, а также для специальных случаев во время выполнения, но помимо этого это просто структура.

1 голос
/ 21 декабря 2011

Обнуляемый тип на самом деле не null, поскольку он по-прежнему не учитывает тот факт, что типы значений не могут быть null.Вместо этого это ссылка на структуру Nullable<> (которая также является типом значения и не может быть null).

Дополнительная информация здесь .

По сути, вы всегда ссылаетесь на экземпляр чего-либо, когда используете обнуляемый тип.Информация по умолчанию, возвращаемая этой ссылкой, является сохраненным значением (или null, если нет сохраненного значения).

1 голос
/ 21 декабря 2011

При использовании int? x = null тогда x назначается новый экземпляр Nullable<int>, а значение ist устанавливается на null.

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

0 голосов
/ 21 декабря 2011

Обнуляемый тип (в данном случае: nullable int) имеет свойство HasValue, которое является логическим. Если значение HasValue равно True, свойство Value (типа T, в данном случае int) будет иметь допустимое значение.

...