Методы обнуляемых типов - PullRequest
0 голосов
/ 05 февраля 2019

Может кто-нибудь объяснить, почему можно вызывать методы на null экземпляре?

int? num = null;

var s1 = num.ToString();
var s2 = num.HasValue;
var s3 = num.GetHashCode();
var s4 = num.GetValueOrDefault();

var s5 = num.Value; // InvalidOperationException
var s6 = num.GetType(); // NullReferenceException

Я могу проверить num is null в режиме отладки, так как это возможно, чтоToString метод или HasValue геттер может быть вызван на null экземпляре, но для Value и GetType это невозможно?Все они являются методами или свойствами типа Nullable<> или нет?

Естественно, что получатель Value возвращает значение null, так же как HasValue возвращает false.Я также ожидал бы, что GetType возвращает Nullable<int> информацию о типе, или num is int? или num is Nullable<int> работает.Почему это не работает?Как я могу проверить, num является обнуляемым типом?

Создание экземпляра ничего не меняет:

Nullable<int> num = new Nullable<int>();

Что скрывается за сценой?

Ответы [ 2 ]

0 голосов
/ 05 февраля 2019

Не совсем ответ, а просто записка.Вы пишете:

Я бы, естественно, ожидал, что Value getter возвращает null значение

Нет!Причина, по которой существует Nullable<T>, заключается в том, чтобы защитить вас от получения значений null без предварительной проверки.

0 голосов
/ 05 февраля 2019

Nullable<T> имеет немного магии компилятора, которая заставляет его выглядеть , как если бы было значение null.Но нет.По сути, поскольку Nullable<T> является типом значения, он не может быть null для начала.Его обнуляемость определяется, есть ли значение или нет.Это означает, что вы можете вызвать HasValue (что важно, так как именно это вставляет компилятор при написании num == null) и другие методы, которые не зависят от присутствующего значения.

Что касаетсяНесколько конкретных моментов:

  • ToString - это реализация, которая работает аналогично тому, как null значения преобразуются в строку при использовании в конкатенации строк, то есть в результате получается пустая строка.Вы также не хотите, чтобы ToString когда-либо выдавал.
  • GetHashCode необходимо поместить Nullable<T> в качестве ключа в словаре или поместить их в хэш-набор.Он также не должен выдавать, поэтому должен возвращать что-то разумное, когда нет значения.
  • Документация объясняет немного базовых концепций.

Доступзначение, когда его нет, запрещено.Как отметили Зохар Пелед и Марк Гравелл ♦ в комментариях, это то, что неявно происходит при вызове GetType:

Казалось бы, логично, чтокомпилятор может просто тихо заменить nullableValue.GetType() на typeof(SomeT?), но тогда это будет означать, что он всегда дает запутанные ответы по сравнению с

object obj = nullableValue;
Type type = obj.GetType()

Можно ожидать, что это будет работать аналогично, но obj.GetType() всегда будетверните либо typeof(T) (не typeof(T?)), либо бросьте NullReferenceException, потому что T? ящики либо в T, либо в null (и вы не можете спросить null, какой это тип)

Отображение конструкций, специально обработанных компилятором, более или менее следующее:

num == null         → !num.HasValue
num != null         → num.HasValue
num = null          → num = new Nullable<int>()
num = 5             → num = new Nullable<int>(5)
(int) num           → num.Value
(object) num        → (object) num.Value         // if HasValue
                    → (object) null              // if !HasValue

Существует дополнительная поддержка операторов, наиболее важно операторов сравнения с ненулевыми значениями Ts и различные операторы, которые работают с потенциальными значениями null, такими как ??, но в этом суть.

...