LINQ Any()和Single()与SingleOrDefault()的空检查

本文关键字:检查 SingleOrDefault Single Any LINQ | 更新日期: 2023-09-27 18:06:47

在什么情况下每个解决方案都优于其他解决方案?

示例1:

if (personList.Any(x => x.Name == "Fox Mulder"))
{
  this.Person = personList.Single(x => x.Name == "Fox Mulder");
}

示例2:

var mulder = personList.SingleOrDefault(x => x.Name == "Fox Mulder");
if (mulder != null)
{
  this.Person = mulder;
}

LINQ Any()和Single()与SingleOrDefault()的空检查

SingleSingleOrDefault都将枚举超过第一个匹配结果的集合,以验证是否只有一个元素匹配标准,并在下一个匹配或集合结束时停止。第一个示例将稍微慢一些,因为Any调用将枚举足够的集合(可能是全部)来确定是否有元素满足条件,在第一次匹配或集合结束时停止。

还有一个关键的区别:第一个例子可能会抛出异常。如果正好有一个, Single将返回匹配的元素,否则抛出异常。使用Any检查并不能验证这一点;它只验证至少有一个

基于这两个原因(主要是/特别是第二个原因),SingleOrDefault方法在这里更可取。

这里有三种情况

情形1:没有项符合条件

选项1:.Any枚举整个集合并返回false;.Single从未执行过。

选项2:.SingleOrDefault枚举整个集合并返回null。

选项本质上是等价的。

案例2:恰好有一项匹配条件

选项1:Any枚举足够的集合以找到单个匹配(可以是第一项,也可以是整个集合)。接下来,Single枚举整个集合以查找该项目,并确认没有其他项目符合条件。

选项2:SingleOrDefault枚举整个集合,返回唯一匹配的。

在这种情况下,选项2更好(正好是一次迭代,与(1,2]迭代相比)

案例3:多个元素符合条件

选项1:Any枚举足够的值来找到第一个匹配。Single枚举了足够的数目来找到第二个匹配项,抛出异常。

选项2:SingleOrDefault枚举足够的值来找到第二个匹配,抛出异常。

都抛出异常,但选项2更快到达。

选项3:

this.Person = personList.FirstOrDefault(x => x.Name == "Fox Mulder");

如果使用实体框架并且name是主键,则:

this.person = db.personList.Find("Fox Mulder");

如果this.Person是空的,或者如果没有找到这个人,你希望this.Person被空覆盖。FirstOrDefault是最快的,因为它会在匹配的第一条记录处停止,而不是遍历整个集合,但是如果找到多条记录,它不会抛出异常。在这种情况下,实体框架解决方案甚至更好,因为Find将使用EF缓存,甚至可能根本不必访问数据源。

isas准则推断:

见下面,从使用'as'CLR中的关键字:

// Bad code - checks type twice for no reason
if (randomObject is TargetType)
{
    TargetType foo = (TargetType) randomObject;
    // Do something with foo
}

通过使用AnySingle,您也检查了两次列表。同样的逻辑似乎也适用:Not only is this checking twice, but it may be checking different things,即,在多线程应用程序中,检查和赋值之间的列表可能不同。在极端情况下,当调用Single时,与Any一起发现的项目可能不再存在。

使用这个逻辑,除非给出相反的证据,否则我将在所有情况下都倾向于例子2。