【问题标题】:Why can't I use the null propagation operator in lambda expressions?为什么我不能在 lambda 表达式中使用空传播运算符?
【发布时间】:2023-03-03 03:43:01
【问题描述】:

我经常在我的代码中使用 null 传播运算符,因为它使我的代码更具可读性,特别是在长查询中,我不必对使用的每个类进行 null 检查。

以下代码抛出编译错误,我们不能在 lambda 中使用空传播运算符。

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

错误:

错误 CS8072 表达式树 lambda 可能不包含空传播运算符。

如果真的不能做其他任何事情,C#可以轻松地将上面的代码转换为下面的代码!

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

我很好奇为什么 C# 什么都不做,只是抛出编译器错误?

【问题讨论】:

  • Foo?.Bar 不等于Foo != null ? Foo.Bar : null,因为Foo 使用空传播运算符计算一次,使用条件计算两次,因此翻译并非在所有情况下都是正确的。
  • 请注意,如果它的代码用于 EF,则您可能并不真正需要空传播运算符,因为当查询转换为 SQL 调用时,SQL 不会抛出空值:- )
  • 注意: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目前不支持?.运算符。

标签: c# .net compiler-errors c#-6.0 null-propagation-operator


【解决方案1】:

这很复杂,因为表达式树 lambda(与委托 lambda 不同)由尚不支持 null 传播的现有 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

您可以深入了解相关的 discussion on CodePlex,其中提供了 3 种解决方案:NullPropagationExpressionConditionalExpression 和混合

【讨论】:

  • 如果某些查询提供程序不支持它,我当然不会感到惊讶,但这不是 C# 语言不支持它的理由。
  • 某些查询提供者尚不支持这一事实并不是禁止all查询的理由曾经的供应商能够使用它。
  • 显然没有查询提供者会花时间来支持处理这样的请求,直到该提供者的用户能够实际创建表示它的表达式树。要支持这一点,首先需要让 lambdas 能够表示它。 存在之后,查询提供者可以开始支持它,因为他们认为这是合适的。也有很多供应商在做各种不同的事情。 EF 并不是世界上唯一的查询提供程序。
  • Expression 的整个 point 是能够在语义上将所有 C# 表达式表示为代码。它并非旨在成为该语言的一小部分。
  • 看来这个问题在 3 年后仍未解决 - 微软现在不应该能够找到时间吗?现在他们似乎有一个坏习惯,就是利用时间和资源作为在 C# 中实现一半新功能的借口。
猜你喜欢
  • 2017-11-24
  • 1970-01-01
  • 2020-06-22
  • 1970-01-01
  • 2023-04-03
  • 2011-09-24
  • 1970-01-01
  • 2020-07-08
  • 2014-01-02
相关资源
最近更新 更多