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

时间:2015-08-06 18:06:54

标签: c# linq

在哪种情况下,每种解决方案都优先于另一种?

示例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;
}

3 个答案:

答案 0 :(得分:8)

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会更快地到达。

答案 1 :(得分:0)

根据is v。as指南进行推断:

请参阅下文Casting vs using the 'as' keyword in the 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,,即,在多线程应用程序中,列表在检查和分配之间可能不同。在极端情况下,当Any调用时,Single找到的项目可能不再存在。

使用这种逻辑,我会赞成在所有情况下的例子2,否则给出证据。

答案 2 :(得分:0)

选项3:

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

如果使用Entity Framework并且name是主键,则:

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

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