Нулевой оператор
var a = b?.cd;
Разве это выражение не должно всегда давать ошибку компиляции? Если b равно нулю, значение null распространяется через, поэтому c также будет равно нулю и, следовательно, также нуждается в этом операторе. В моем понимании использование этого оператора в выражении распространяется вирусно.
Но ни Visual Studio 2015, ни Resharper мне ничего не говорят, я что-то здесь упускаю?
4 ответа
Оператор просто синтаксический сахар для этого:
MyType a = b == null ?
null:
b.c.d;
Почему это должно привести к ошибке компиляции, мне неясно.
Если b равно нулю, значение null распространяется через, поэтому c также будет равно нулю и, следовательно, также потребуется этот оператор
Это не правда На самом деле, когда b
нулевой c
даже не существует, так как нет экземпляра, на котором этот член мог бы существовать. Короче оператор просто возвращается null
и опускает оценку c
или даже d
дальше
Этот оператор делает короткое замыкание и возвращает null
в случае b
является null
,
var a = b == null ? null : b.c.d
Вот как это утверждение выглядело бы по-старому: ?.
Оператор не смотрит глубже, когда то, что находится до того, как он становится нулевым, он просто возвращает ноль, однако вы получите ошибку, где b
определяется, но b.c == null
так как ты не писал как var a = b?.c?.d
,
Обратите внимание, что:
var a1 = b?.c.d;
полностью отличается от:
var a2 = (b?.c).d;
Не очень легко объяснить вкратце, как унарный оператор ?.
работает (да, одинарный!). Но идея в том, что остальная часть "цепочки" "операций" пропускается, если выражение до ?.
нулевой.
Таким образом, для a1
, вы получаете нуль типа времени компиляции, переносимого членом d
(или же Nullable<>
такого типа, если это необходимо) всякий раз, когда b
бывает нулевым. когда b
бывает ненулевым, вы получаете то же самое, что и b.c.d
который может потерпеть неудачу, если b.c
нулевой.
Но a2
совсем другое. Это всегда взорвется, если b
является нулевым, потому что тогда скобка (b?.c)
будет нулевой ссылкой, а следующий .
оператор приведет к NullReferenceException
, (Я предполагаю, что здесь c
имеет тип ссылки во время компиляции.)
Так что не думайте, что существует какая-то "левая ассоциативность", которая делает b?.c.d
эквивалентно (b?.c).d
!
Вы можете найти ссылку на предварительную Спецификацию языка C# в этом ответе в другой ветке; в качестве унарного оператора они упоминают нуль-условный оператор в § 7.7.1.