为什么不能在lambda表达式中使用null传播运算符?


102

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

以下代码引发了一个编译错误,我们不能在lambda中使用null传播运算符。

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#什么都不做,只是抛出编译器错误?


4
Foo?.Bar不等价,Foo != null ? Foo.Bar : null因为Foo使用null传播运算符对它进行了一次评估,使用条件条件进行了两次评估,因此转换并非在所有情况下都是正确的。
Lucas Trzesniewski 2015年

3
请注意,如果将其代码用于EF,则有可能您真的不需要null传播运算符,因为当查询转换为SQL调用时,SQL不会抛出null :-)
xanatos

注意:因为EF当前不支持运算符,所以写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?.
马特

Answers:


72

这很复杂,因为表达式树lambda(与委托lambda不同)是由现有的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个解决方案可供选择:NullPropagationExpressionConditionalExpression和混合


23
如果某些查询提供程序不支持它,我当然不会感到惊讶,但这不是没有C#语言支持它的原因。
Servy 2015年

16
这一事实某些查询供应商还不支持它不是一个理由,禁止所有来自查询供应商曾经能够使用它。
Servy 2015年

10
显然,没有查询提供者会花时间来支持处理此类请求,直到该提供者的用户能够实际创建表示该请求的表达式树为止。为了支持这一点,首先要做的是让lambda能够表示它。 这种情况存在之后,查询提供者就可以开始支持它,因为他们认为这是适当的。还有很多提供者正在做各种各样的事情。并非EF是世界上唯一的查询提供程序。
Servy 2015年

7
Expression是能够从语义上代表所有的C#表达式作为代码。它不只是语言的一小部分。
Servy 2015年

6
三年后,这种解决方案似乎仍未解决-微软现在是否应该找不到时间?如今,他们似乎有一种不良习惯,即以时间和资源作为在C#中一半实现新功能的借口。
NetMage
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.