示例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;
}
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;
}
Single
和 SingleOrDefault
都会枚举集合中第一个匹配结果之后的元素,以验证准确存在一个符合条件的元素,最终停止于下一个匹配项或集合末尾。第一个例子稍微慢一些,因为 Any
调用将枚举足够多的集合(有可能是全部)来确定是否有任何元素满足条件,最终停止于第一个匹配项或集合末尾。
还有一个关键区别:第一个例子可能会抛出异常, Single
在恰好有一个匹配项时返回匹配元素,并在没有匹配项时抛出异常。而使用 Any
不能验证这一点,它只验证是否至少有一个匹配项。
基于这两个原因(特别是第二个原因),这里首选使用 SingleOrDefault
方法。
所以这里有三种情况:
情况1:没有任何项符合条件
选项1:.Any
枚举整个集合并返回 false;.Single
不执行。
选项2:.SingleOrDefault
枚举整个集合并返回 null。
两者实质上是等价的。
情况2:只有一项符合条件
选项1:Any
枚举集合中足够多的元素以找到单个匹配项(可以是第一个元素,也可能是整个集合)。接下来,Single
枚举整个集合以找到该项并确认没有其他匹配项。
选项2:SingleOrDefault
枚举整个集合,返回唯一的匹配项。
在这种情况下,选项2 更好(仅需一次迭代,而选项1和2需要 1 到 2 次迭代)。
情况3:有多项元素符合条件
选项1: Any
枚举足够找到第一次匹配。 Single
枚举足够找到第二次匹配,抛出异常。
选项2: SingleOrDefault
枚举足够找到第二次匹配,抛出异常。
两者都会抛出异常,但选项2会更快地到达。
Single
和SingleOrDefault
不会枚举整个集合 - 如果找到第二个元素,则停止枚举就足够了。 - Jacob Krall从 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
}
通过使用Any
和Single
,您也会检查两次列表。同样的逻辑似乎也适用:这不仅检查两次,而且可能检查不同的东西,
即在多线程应用程序中,列表在检查和分配之间可能是不同的。在极端情况下,使用Any
找到的项目在调用Single
时可能已经不存在。
基于这种逻辑,除非有证据证明否则,我会在所有情况下更喜欢第二个示例。
选项3:
this.Person = personList.FirstOrDefault(x => x.Name == "Fox Mulder");
this.person = db.personList.Find("Fox Mulder");
如果this.Person
为空或者找不到人,这两个都可以工作,你期望this.Person
被覆盖为null。FirstOrDefault是最快的,因为它会在第一个匹配的记录处停止而不是遍历整个集合,但如果找到多个,则不会抛出异常。在这种情况下,实体框架解决方案甚至更好,因为Find将使用EF缓存,可能根本不需要访问数据源。
SingleOrDefault
比Any
更高效。当涉及到Linq时,通常有多种方法可以完成同一件事情。我会选择对你来说最有意义的选项。 - Alex Booker