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


当前回答

我查询了谷歌在GitHub上不同方法的使用情况。这是通过对每个方法运行谷歌搜索查询,并通过使用查询“site:github.com file:cs…”来限制查询到github.com域和.cs文件扩展名。

似乎第一个*方法比单一*方法更常用。

| Method               | Results |
|----------------------|---------|
| FirstAsync           |     315 |
| SingleAsync          |     166 |
| FirstOrDefaultAsync  |     357 |
| SingleOrDefaultAsync |     237 |
| FirstOrDefault       |   17400 |
| SingleOrDefault      |    2950 |

其他回答

我查询了谷歌在GitHub上不同方法的使用情况。这是通过对每个方法运行谷歌搜索查询,并通过使用查询“site:github.com file:cs…”来限制查询到github.com域和.cs文件扩展名。

似乎第一个*方法比单一*方法更常用。

| Method               | Results |
|----------------------|---------|
| FirstAsync           |     315 |
| SingleAsync          |     166 |
| FirstOrDefaultAsync  |     357 |
| SingleOrDefaultAsync |     237 |
| FirstOrDefault       |   17400 |
| SingleOrDefault      |    2950 |

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.

没有人提到SQL中转换的FirstOrDefault执行TOP 1记录,而SingleOrDefault执行TOP 2记录,因为它需要知道是否有多个记录。

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

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

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

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

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

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

结论:

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

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

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

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

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