考虑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()时,你遵循或建议什么约定?


当前回答

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.

其他回答

我使用SingleOrDefault的情况下,我的逻辑将是零或一个结果。如果有更多,这是一个错误的情况,这是有帮助的。

在上一个例子中:

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

是的。如果您尝试使用SingleOrDefault()并且查询结果超过记录,您将得到一个异常。你唯一可以安全使用SingleOrDefault()的时候是当你只期望1和只有1个结果…

SingleOrDefault:您的意思是“最多”有一个项与查询或默认值匹配 FirstOrDefault:您的意思是有“至少”一项与查询或默认值匹配

下次你需要选择的时候大声说出来,你可能会做出明智的选择。:)

在回答中漏掉了一件事....

如果有多个结果,没有排序by的FirstOrDefault可以根据服务器碰巧使用的索引策略返回不同的结果。

就我个人而言,我无法忍受在代码中看到FirstOrDefault,因为对我来说,这表明开发人员不关心结果。通过命令,它可以作为一种强制执行最新/最早的方式。我不得不纠正许多由于粗心的开发人员使用FirstOrDefault而引起的问题。

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

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