在哪种情况下,每种解决方案都优先于另一种?
示例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;
}
答案 0 :(得分:8)
Single
和SingleOrDefault
都会枚举超出第一个匹配结果的集合,以验证是否只有一个符合条件的元素,在下一个匹配或集合结束时停止。第一个示例稍微慢一些,因为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
}
使用Any
和Single
,您还要检查列表两次。并且相同的逻辑似乎适用: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缓存,甚至可能根本不需要访问数据源。