考虑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

其他回答

语义上的差异 性能差异

两者之间。

语义的区别:

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

性能差异

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

结论

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

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

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

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

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

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

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

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

在上一个例子中:

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

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