Почему я не могу использовать оператор нулевого распространения в лямбда-выражениях?

103

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

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

var cnt = humans.AsQueryable().Count(a => a.House?[0].Price == 5000);

Ошибка :

Ошибка CS8072 Лямбда-выражение дерева не может содержать пустой оператор распространения.

C # Может легко преобразовать приведенный выше код в следующий код, если действительно ничего не может сделать!

var cnt = humans.AsQueryable().Count(a => a.House != null && a.House[0].Price == 5000);

Мне любопытно, почему C # ничего не делает и просто выдает ошибку компилятора?

Мохсен Саркар
источник
4
Foo?.Barне эквивалентно, Foo != null ? Foo.Bar : nullпотому что Fooвычисляется один раз с помощью оператора распространения нуля и дважды с условным условием, поэтому перевод будет правильным во всех случаях.
Лукас Тшесневски
3
Обратите внимание, что если это код для EF, есть вероятность, что вам действительно не нужен оператор распространения нуля, потому что, когда запрос преобразуется в вызов SQL, SQL не
генерирует
NB: Было бы также полезно писать var q = from c in Categories join p in Products on c equals p.Category into ps from p in ps.DefaultIfEmpty() select new { Category = c, ProductName = (p?.ProductName)??"(No products)"};вместо того, чтобы писать, ProductName = (p == null) ? "(No products)" : p.ProductNameпотому что EF в настоящее время не поддерживает ?.оператор.
Мэтт

Ответы:

72

Это сложно, поскольку лямбда-выражения дерева выражений (в отличие от лямбда-выражений-делегатов) интерпретируются уже существующими поставщиками LINQ, которые еще не поддерживают распространение NULL.

Преобразование в условное выражение не всегда является точным, поскольку существует несколько оценок, в то время как с ?.использованием только одной оценки, например:

customer.Where(a => c.Increment()?.Name) // Written by the user 
customer.Where(a => c.Increment() == null ? null : c.Increment().Name) // Incorrectly interpreted by an old LINQ provider

Вы можете углубиться в соответствующей дискуссии на CodePlex , где предлагаются 3 решения: NullPropagationExpression, ConditionalExpressionи гибрид

i3arnon
источник
26
Я, конечно, не удивлюсь, если некоторые поставщики запросов не смогут его поддерживать, но это не повод не поддерживать его в языке C #.
Servy 05
18
Тот факт, что некоторые поставщики запросов еще не поддерживают его, не является причиной запрещать всем поставщикам запросов когда-либо использовать его.
Servy 05
11
И, очевидно, ни один провайдер запросов не будет тратить время на поддержку обработки такого запроса, пока пользователи этого провайдера не смогут фактически создавать деревья выражений, которые его представляют. Чтобы это поддерживалось, первое, что нужно сделать, - это чтобы лямбды могли это представлять. После этого поставщики запросов могут начать поддерживать его, если сочтут это целесообразным. Есть также много провайдеров, которые занимаются самыми разными вещами. Не то чтобы EF - единственный в мире поставщик запросов.
Servy 05
8
Весь смысл в Expressionтом, чтобы иметь возможность семантически представлять все выражения C # в виде кода. Он не предназначен для использования в качестве небольшого подмножества языка.
Servy
7
Кажется, что это все еще не решено 3 года спустя - разве Microsoft не могла найти время к настоящему времени? Похоже, что в наши дни у них есть дурная привычка использовать время и ресурсы как предлог для того, чтобы наполовину внедрять новые функции в C #.
NetMage