如何对布尔条件进行null coalescing?

16

我试图安全地检查一个 IList<> 是否为空。

var Foo = Bar.GimmeIListT(); // Returns an IList<SomeObject>
if (Foo?.Any())
    // Do cool stuff with items in Foo

但条件存在一个错误:

无法隐式转换 'bool?' 到 'bool'。存在一个显式转换 (您是否缺少强制类型转换?)

看起来条件计算出一个可空的布尔值,所以我尝试

if (Foo?.Any().Value())

但这也不好:

“bool”不包含“Value”的定义,也没有扩展.... blah blah blah

因此,在第一个示例中,它抱怨它是可空的bool,但在第二个示例中则抱怨它不是。

作为另一种方法,我尝试:

if (Foo?.Any() == true)

这个代码是可以正常运行的 - 但它不应该工作,因为它使用了一个隐式转换,而第一个信息说它不想要这种方式!

到底发生了什么?正确的做法是什么?


如果 (Foo?.Count > 0) { } - Andzej Maciusovic
1
@AndzejMaciusovic:这种方式不太好。如果Foo实际上是一个需要花费数小时才能完全执行的查询,你将非常需要Any。如果你想知道是否至少有一个,就不要全部计算。 - Tim Schmelter
1
@TimSchmelter 在我的示例中,我使用的是.Count而不是Count()。.Count是在IList上已经计算好的字段,事实上使用.Count比.List上的.Any()快一些。 - Andzej Maciusovic
2
@AndzejMaciusovic:没错,但人们通常会将其视为一种好的方式,并忽略括号的缺失(在VB.NET中它们是可选的)。 - Tim Schmelter
4个回答

19

如果使用 ==,您可以将其与 bool? 进行比较,这确实是最好/最简单的方法:

if (Foo?.Any() == true) ...
关于为什么不能在if中使用==,但可以使用bool,Jon Skeet在这里有更好的解释:

Nullable<bool>不能隐式转换为bool。从boolNullable<bool>有一个隐式转换, 这就是第一版本中每个布尔常量发生的情况(用语言术语来说)。然后应用了bool operator==(Nullable<bool>, Nullable<bool>)操作符。(这与其他提升运算符不完全相同 - 结果只是bool,而不是Nullable<bool>)。

换句话说,表达式fred == false的类型为bool, 而表达式fred的类型为Nullable<bool>,因此您不能将其用作“if”表达式。

所以if只允许使用bool,而您有一个bool?,但是==操作符将bool转换为bool?,因此您可以比较两个bool?

2
OP已经尝试过这个了_这个确实有效 - 但不应该,因为它使用了第一条消息中所说的不想要的隐式转换!_ - Pikoh
1
@Pikoh:已修复 :) - Tim Schmelter
1
使用 @JonSkeet 的卡片啊? :) 好的,现在就解释了,+1。 - Pikoh

3

编辑:

看起来bool?的原因是Foo?.Any()本身。 如果您不想将其与true进行比较,我建议您使用临时变量:

bool? any = Foo?.Any(); 
if (any.Value) ...

另外,如果对象是一个类,您可以使用 FirstOrDefault() != null 作为检查条件。它不会花费很多时间,因为它只会获取第一个对象:

if (Foot?.FirstOrDefault() != null)...

我会选择使用临时变量或者Foo?.Any() == true选项。 原文: 注意:我也很惊讶,if (a?.Any())后面不能跟.Value()或者.Value(!)。
我认为你需要的是没有()(方法)的Value(属性):
if (Foo?.Any()?.Value) ... 

bool?有一个.Value(属性),它是一个bool类型。


3

Any()返回bool,但Foo?.Any()将返回bool?

因此,Foo?.Any().Value无法编译,因为Any()返回一个没有成员Valuebool

如果Foonull,则不会执行Any(),因为该语句将在解释?.运算符后面的部分之前返回null

但是,如果将Foo?.Any()放在括号中,您就可以使用bool?类型的结果,并通过ValueGetValueOrDefault()进行检查:

(Foo?.Any()).GetValueOrDefault()

2
更多的语法糖,空值合并运算符。C# 8.0或更高版本。
if (Foo?.Any() ?? false) { }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接