С# Безопасный навигационный оператор - что на самом деле происходит?
Я с интересом следил за функцией безопасного навигатора, добавленной в С# 6. Я с нетерпением жду этого какое-то время. Но я нахожу другое поведение, чем я ожидал. Я понимаю, что я действительно не понимаю, как это работает.
Учитывая этот класс
class Foo {
public int? Measure;
}
Вот некоторый код с использованием нового оператора.
Foo f = new Foo { Measure = 3 };
Console.WriteLine(f?.Measure); // 3
f = new Foo { Measure = null };
Console.WriteLine(f?.Measure); // null
f = null;
Console.WriteLine(f?.Measure); // null
До сих пор все работает как ожидалось. ?.
обращается к членам, когда левая сторона не равна нулю, в противном случае возвращается значение null. Но здесь все идет в направлении, которого я не ожидал.
var i = f?.Measure; // i is Nullable<int>
Console.WriteLine(i.HasValue); // false
Console.WriteLine(f?.Measure.HasValue); // null
Что?
Почему я могу получить HasValue
из i
, но не из того же выражения, которое я присвоил i
? Как HasValue
когда-либо быть нулевым?
Изменить: мой реальный вопрос касается поведения программы, а не ошибки компиляции. Я удалил лишний материал о компиляции и более подробно остановился на этом вопросе, почему два разных результата возвращаются по той же логике.
Ответы
Ответ 1
Проследите это логически.
var f = ???;
var i = f?.Measure;
var t = i.HasValue;
Мы не знаем, является ли f
нулевым или нет.
1. Если f
null, то результат (i
) равен null
2. Если f
не null, то результатом (i
) является int
Следовательно, i
определяется как int?
, а t
- это bool
Теперь, пройдем через это:
var f = ???;
var i = f?.Measure.HasValue;
- Если
f
- null, то результат (i
) равен null
- Если
f
не null, то результатом (i
) является Measure.HasValue
, что является bool.
Следовательно, i
является bool?
.
Если f
равно null, мы коротко замыкаем и возвращаем null. Если это не так, мы возвращаем результат bool
.HasValue
.
По существу, при использовании ?.
- возвращаемый тип должен быть опорным значением или Nullable<T>
, так как выражение может коротко замыкаться, чтобы вернуть значение null.
Ответ 2
Nullable<T>
на самом деле является структурой и поэтому не может быть нулевым, только его Value
может, поэтому HasValue
всегда будет доступен.
Ответ 3
var i = f?.Measure; // i is Nullable<int>
Console.WriteLine(i.HasValue); // false
Console.WriteLine(f?.Measure.HasValue); // null
В этом случае f равно null.
Причина, по которой i.HasValue
возвращает false
, потому что i
имеет тип Nullable<int>
. Поэтому даже когда значение i
равно null, как и в этом случае, i.HasValue
все еще доступен.
Тем не менее, f?.Measure.HasValue
сразу возвращает null
после оценки f?
. Следовательно, результат вы видите выше.
Просто чтобы процитировать комментарий Роба:
Главное, чтобы понять, что вы читаете и понимаете это: f?.Measure.HasValue как это: (f?.Measure).HasValue, который он нет.