考虑IEnumerable扩展方法SingleOrDefault()和FirstOrDefault()

MSDN文档SingleOrDefault:

返回序列中唯一的元素,如果序列为空则返回默认值;如果序列中有多个元素,此方法将引发异常。

而来自MSDN的FirstOrDefault(假设在使用OrderBy()或orderbydescent()或根本不使用时),

返回序列的第一个元素

考虑一些示例查询,并不总是清楚何时使用这两个方法:

var someCust = db.Customers
.SingleOrDefault(c=>c.ID == 5); //unlikely(?) to be more than one, but technically COULD BE

var bobbyCust = db.Customers
.FirstOrDefault(c=>c.FirstName == "Bobby"); //clearly could be one or many, so use First?

var latestCust = db.Customers
.OrderByDescending(x=> x.CreatedOn)
.FirstOrDefault();//Single or First, or does it matter?

问题

当你决定在LINQ查询中使用SingleOrDefault()和FirstOrDefault()时,你遵循或建议什么约定?


当前回答

如果结果集返回0条记录:

SingleOrDefault返回类型的默认值(例如int的默认值为0) FirstOrDefault返回类型的默认值

如果结果集返回1条记录:

SingleOrDefault返回该记录 FirstOrDefault返回该记录

如果你的结果集返回很多记录:

SingleOrDefault抛出异常 FirstOrDefault返回第一条记录

结论:

如果希望在结果集包含许多记录时抛出异常,请使用SingleOrDefault。

如果无论结果集包含什么,您总是想要1条记录,请使用FirstOrDefault

其他回答

如果结果集返回0条记录:

SingleOrDefault返回类型的默认值(例如int的默认值为0) FirstOrDefault返回类型的默认值

如果结果集返回1条记录:

SingleOrDefault返回该记录 FirstOrDefault返回该记录

如果你的结果集返回很多记录:

SingleOrDefault抛出异常 FirstOrDefault返回第一条记录

结论:

如果希望在结果集包含许多记录时抛出异常,请使用SingleOrDefault。

如果无论结果集包含什么,您总是想要1条记录,请使用FirstOrDefault

语义上的差异 性能差异

两者之间。

语义的区别:

FirstOrDefault返回可能有多个的第一项(如果不存在则返回default)。 SingleOrDefault假设有一个单项并返回它(如果不存在则返回default)。多个项目违反合同,抛出异常。

性能差异

FirstOrDefault通常更快,它迭代直到找到元素,只有在找不到元素时才迭代整个枚举对象。在许多情况下,有很大的可能性找到一个项目。 SingleOrDefault需要检查是否只有一个元素,因此总是迭代整个枚举对象。准确地说,它迭代直到找到第二个元素并抛出异常。但在大多数情况下,没有第二个元素。

结论

如果你不关心有多少项,或者当你无法负担检查唯一性的费用时(例如在一个非常大的集合中),请使用FirstOrDefault。当您在将项添加到集合时检查唯一性时,在搜索这些项时再次检查它可能代价太大。 如果您不需要太关心性能,并且希望确保单个项的假设对读者来说是清楚的,并在运行时进行检查,则使用SingleOrDefault。

在实践中,即使在假设单个项的情况下,也经常使用First / FirstOrDefault来提高性能。您仍然应该记住,Single / SingleOrDefault可以提高可读性(因为它声明了单个项的假设)和稳定性(因为它检查了它),并适当地使用它。

在你的情况下,我会使用以下方法:

select by ID==5:在这里使用SingleOrDefault是可以的,因为你希望有一个[或没有]实体,如果你有多个ID为5的实体,那就有问题了,肯定值得异常处理。

当搜索名字等于“Bobby”的人时,可能会有不止一个(我认为很有可能),所以你既不应该使用Single也不应该使用first,只需使用where操作选择(如果“Bobby”返回太多实体,用户必须优化他的搜索或选择返回的结果之一)

按创建日期的顺序也应该执行一个where操作(不太可能只有一个实体,排序不会有太大的用处;)这意味着你想要所有的实体排序-如果你想要一个,使用FirstOrDefault, Single会抛出每次如果你有多个实体。

我不明白为什么你要使用FirstOrDefault(x=> x.ID == key),当你使用Find(key)可以更快地检索结果时。如果使用表的Primary键进行查询,经验法则是始终使用Find(key)。FirstOrDefault应该用于谓词,如(x=> x. username == username)等。

这个问题的标题并不专门针对DB上的linq或linq到List/IEnumerable等,所以不应该被否决。

In my opinion FirstOrDefault is being overused a lot. In the majority of the cases when you’re filtering data you would either expect to get back a collection of elements matching the logical condition or a single unique element by its unique identifier – such as a user, book, post etc... That’s why we can even get as far as saying that FirstOrDefault() is a code smell not because there is something wrong with it but because it’s being used way too often. This blog post explores the topic in details. IMO most of the times SingleOrDefault() is a much better alternative so watch out for this mistake and make sure you use the most appropriate method that clearly represents your contract and expectations.