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


当前回答

在上一个例子中:

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

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

其他回答

从本质上讲,这给了你某种验证来清理你的数据,如果你选择其中一个,它会同时给出数据,但SingleOrDefault会让你意识到,当你期望的数据应该只有1个结果,并吐出更多的1,那么你需要看看为什么你的存储过程或查询导致这样,重复的项目在查询中从来都不好。

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.

在上一个例子中:

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

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

语义上的差异 性能差异

两者之间。

语义的区别:

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

性能差异

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

结论

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

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

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

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

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