我经常在我的代码中使用 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
使用 null 传播运算符计算一次,然后使用条件计算两次,因此翻译并非在所有情况下都是正确的。
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 当前不支持 ?.
运算符。
这很复杂,因为表达式树 lambdas(与委托 lambdas 不同)由尚不支持 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 种解决方案:NullPropagationExpression
、ConditionalExpression
&混合动力车
Expression
的整个point 是能够在语义上将所有 C# 表达式表示为代码。它的设计目的不仅仅是语言的一小部分。