LINQ单对第一

LINQ:

当我确定查询会返回单个logging时,使用Single()运算符比First()更有效吗?

有区别吗?

如果您期待Singlelogging,那么在代码中明确表示总是很好的。

我知道其他人已经写了你为什么使用其中一个,但我想我会说明为什么你不应该使用一个,当你的意思是另一个。

注意:在我的代码中,我通常会使用FirstOrDefault()SingleOrDefault()但这是一个不同的问题。

例如,以一个使用复合键( IDLang )的不同语言存储Customers的表格为例:

 DBContext db = new DBContext(); Customer customer = db.Customers.Where( c=> c.ID == 5 ).First(); 

上面的代码引入了一个可能的逻辑错误(难以追踪)。 它会返回多个logging(假设你有多种语言的客户logging),但它总是只返回第一个logging……有时可能有效……但不是其他logging。 这是不可预测的。

由于您的意图是返回一个单一的Customer使用Single() ;

以下将抛出一个exception(这是你在这种情况下):

 DBContext db = new DBContext(); Customer customer = db.Customers.Where( c=> c.ID == 5 ).Single(); 

然后,你只要打在自己的额头上,并对自己说… OOPS! 我忘了语言领域! 以下是正确的版本:

 DBContext db = new DBContext(); Customer customer = db.Customers.Where( c=> c.ID == 5 && c.Lang == "en" ).Single(); 

First()在以下场景中很有用:

 DBContext db = new DBContext(); NewsItem newsitem = db.NewsItems.OrderByDescending( n => n.AddedDate ).First(); 

它将返回一个对象,因为你正在使用sorting,它将是最近的logging被返回。

使用Single()当你觉得它应该显式地总是返回1logging将帮助你避免逻辑错误。

如果find多个匹配条件的logging,Single将抛出exception。 首先将始终从列表中select第一条logging。 如果查询只返回1条logging,则可以使用First()

如果集合是空的,两者都会抛出一个InvalidOperationExceptionexception。 或者,您可以使用SingleOrDefault() 。 如果列表为空,这不会引发exception

这两种方法之间存在细微的语义差异。

使用Single从一个应该包含一个元素的序列中检索第一个(也是唯一的)元素。 如果序列有多于on的元素,那么你调用Single将导致一个exception被抛出,因为你指出应该只有一个元素。

使用First可从包含任意数量元素的序列中检索第一个元素。 如果序列有多于on元素,那么First的调用将不会引发exception,因为您表示只需要序列中的第一个元素,而不在乎是否存在更多元素。

如果序列不包含任何元素,那么这两个方法调用都会导致抛出exception,因为这两个方法至less需要一个元素。

如果我记得,Single()会检查第一个元素之后是否有另一个元素(如果是这种情况,则抛出exception),而First()在获取它之后停止。 如果序列为空,则都会抛出exception。

Personnally,我总是使用First()。

单()

返回查询的单个特定元素

使用时 :如果预计只有一个元素, 不是0或大于1.如果列表为空或有多个元素,则会抛出exception“序列包含多个元素”

的SingleOrDefault()

返回查询的单个特定元素,如果未find结果,则返回默认值

使用时 :预计有0或1个元素时。 如果列表中有2个或更多的项目,它将会抛出exception。

第一()

返回具有多个结果的查询的第一个元素。

使用时 :当预计有一个或多个元素时,只需要第一个元素。 如果列表中不包含任何元素,它将抛出一个exception。

FirstOrDefault()

返回任意数量元素的列表的第一个元素,如果列表为空,则返回一个默认值。

使用时 :预计有多个元素时,只需要第一个元素。 或者列表是空的,你想要一个指定types的默认值,和default(MyObjectType) 。 例如:如果列表types是list<int> ,它将返回列表中的第一个数字,如果列表为空,则返回0。 如果是list<string> ,它将返回列表中的第一个string,如果列表为空,则返回null。

如果您不特别需要在有多个项目的情况下引发exception,请使用First()

两者都是高效的,拿第一个项目。 First()稍微高效一点,因为它不会检查是否有第二个项目。

唯一的区别是Single()期望在枚举中只有一个项目开始,如果有多个项目,将会抛出一个exception。 如果在这种情况下特别需要引发exception 使用 .Single()

关于性能:我和一个同事正在讨论Single vs First(或SingleOrDefault vs FirstOrDefault)的性能,而且我争辩说First(或FirstOrDefault)会更快并且性能更好(我全部都是关于使我们的应用程序跑得更快)。

我已经阅读了Stack Overflow上的几篇关于这个问题的文章。 有人说使用First而不是Single可以获得很小的性能提升。 这是因为First会简单地返回第一个项目,而Single必须扫描所有结果以确保没有重复(即:如果在表格的第一行中find该项目,它仍然会扫描每一行到确保没有第二个值匹配的条件,然后会抛出一个错误)。 我觉得自己在“第一”比“单”快,所以我着手certificate这一点,让辩论rest。

我在我的数据库中设置了一个testing,并添加了1,000,000行ID UniqueIdentifier Foreign UniqueIdentifier Info nvarchar(50)(填充数字string“0”到“999,9999”

我加载数据并将ID设置为主键字段。

使用LinqPad,我的目标是显示如果您使用Singlesearch“Foreign”或“Info”的值,则会比使用First更糟糕。

我无法解释我得到的结果。 在几乎所有情况下,使用Single或SingleOrDefault稍快。 这对我来说没有任何逻辑意义,但我想分享一下。

例如:我使用了以下查询:

 var q = TestTables.First(x=>x.Info == "314638") ; //Vs. Var q = TestTables.Single(x=>x.Info =="314638") ; //(this was slightly faster to my surprise) 

我对“外国”关键字段进行了类似的查询,这个字段没有被索引,认为First会更快,但Single在我的testing中总是稍微快一点。

他们是不同的。 他们都声称结果集不是空的,但是单个也声明结果不会超过1个。 我个人使用单一的情况下,我只希望有1结果只是因为得到超过1个结果是错误的,可能应该被视为这样的。

很多我认识的人使用FirstOrDefault(),但我更倾向于使用SingleOrDefault(),因为如果有多个数据通常会是某种数据不一致。 这是处理LINQ到对象,但。

你可以尝试一个简单的例子来获得差异。 第三行将抛出exception;

  List<int> records = new List<int>{1,1,3,4,5,6}; var record = records.First(x => x == 1); record = records.Single(x => x == 1);