C# 6.0 условный оператор null в операторах if

Может кто-нибудь объяснить логику условного оператора null в операторах if?

Представьте себе следующий код

List<string> items = null;
if (items?.Count == 0)
{
    Console.WriteLine("error");
}
else
{
    Console.WriteLine("OK");
}

Приведенное выше будет печатать OK. Почему он компилируется, если следующий блок не компилируется?

if (items?.Any())    // won't compile but if (items?.Count() == 0) would
{
    ...
}

Я угадываю ?. остановит выполнение при обнаружении нуля и пропустит весь if, но почему это не так с ?.Any()? Просто потому, что это метод, а count — свойство?

И почему метод расширения Linq Any() требует явного преобразования из Nullable в bool, где Count() == 0 компилируется без преобразования Nullable в int?


person David    schedule 06.05.2021    source источник
comment
Существует перегрузка для ==, чтобы отменить сравнение и по-прежнему возвращать true/false, поэтому магия заключается в операторе == для Nullable<T>. Если вы попробуете if (items?.Any() == true), он скомпилируется.   -  person Lasse V. Karlsen    schedule 06.05.2021
comment
Обратите внимание, что в C# 9 это можно записать как if (items is { Count: > 0 }). Вы можете или не можете найти это яснее.   -  person canton7    schedule 06.05.2021


Ответы (2)


если items равно null, то items?.Count тоже равно null.
а null == 0 — это сравнение, которое приводит к ложному результату. так что if доволен.

но items?.Any() также будет нулевым, а if(null) недопустимым, потому что нуль не является логическим значением и не может быть преобразован в единицу.

поэтому вам просто нужно указать резервное логическое значение:

if (items?.Any() ?? false) {

}

сделает свое дело

person Franz Gleichmann    schedule 06.05.2021
comment
if (items?.Any() == true) читабельнее, я думаю - person Hans Kilian; 06.05.2021
comment
@HansKilian, это вопрос предпочтений, я (очевидно) сторонник нулевого оператора объединения. но было бы интересно посмотреть, есть ли разница в производительности. - person Franz Gleichmann; 06.05.2021
comment
Я думаю, что читабельность, как правило, важнее, чем производительность. По крайней мере, в тех системах, над которыми я работаю. Я оставляю компилятору производительность :) Но вы, конечно, правы, что более читабельно - это вопрос предпочтений. - person Hans Kilian; 06.05.2021
comment
Спасибо @FranzGleichmann, теперь это имеет смысл. Я не понял, что вы можете сделать if (null == 0), что кажется странным, но объясняет, почему он доволен if (items?.Count == 0). - person David; 06.05.2021
comment
There's no difference in performance - person canton7; 06.05.2021
comment
@David Это потому, что и 0, и null можно преобразовать в int? (целое число, допускающее значение NULL). - person canton7; 06.05.2021
comment
@David хорошо, если это отвечает на ваш вопрос, то голосование и принятие - традиционная реакция;) - person Franz Gleichmann; 06.05.2021
comment
Конечно, спасибо, ребята. - person David; 06.05.2021

Рассмотрим случай null.

В if (items?.Count == 0) это становится if (null == 0) и дает false.

Но в if (items?.Any()) оно становится if (null), а это неверно.

Вы можете использовать if (items?.Any() == true) или if (items?.Any() ?? false) или что-то подобное.

Я заметил, что items.Count == 0 является ошибкой, но items == null возвращает OK в вашем первом примере.
Это странно.

person Henk Holterman    schedule 06.05.2021