Чому я не можу використовувати оператор нульового поширення в лямбда-виразах?


102

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

У наведеному нижче коді виникає помилка компіляції, що ми не можемо використовувати оператор поширення нуля в лямбда.

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 не кидає нулі :-)
xanatos

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, які ще не підтримують нульове поширення.

Перетворення в умовний вираз не завжди є точним, оскільки існує декілька обчислень, тоді як, наприклад, ?.існує лише одне обчислення:

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і гібрид


23
Я, звичайно, не був би здивований, якщо певні постачальники запитів не змогли б його підтримати, але це не причина, коли мова C # не підтримує його.
Сервіс

16
Те, що певні постачальники запитів поки не підтримують, це не є причиною забороняти всім постачальникам запитів будь-коли мати можливість їх використовувати.
Сервіс

10
І очевидно, жоден постачальник запитів не збирається витрачати час на підтримку обробки такого запиту, поки користувачі цього постачальника не зможуть створити дерева виразів, які його представляють. Щоб це було підтримано, перше, що має відбутися, - це лямбди, які зможуть це представляти. Після того, як це існує, постачальники запитів можуть почати його підтримувати, як вони вважають це доцільним. Там також багато постачальників, які роблять всілякі різні речі. Це не так, як EF є єдиним постачальником запитів у світі.
Серві

7
Вся справа в Expressionтому, щоб мати можливість представляти всі вирази C # семантично як код. Це не розроблено, щоб бути просто якоюсь невеликою підмножиною мови.
Серві 05.03.15

6
Здається, це все ще не вирішено через 3 роки - хіба Microsoft не змогла знайти час до цього часу? Вони, схоже, мають погану звичку використовувати час та ресурси як привід для напівзапровадження нових функцій у C # в наші дні.
NetMage
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.