使用LINQ Where vs. Find从业务对象列表中检索给定业务对象的正确方法是什么?

时间:2012-05-24 15:24:07

标签: c# linq

假设我有以下项目清单:

List<Item> items = Item.GetSomeItems();

我想从项目列表中检索具有ID的特定项目:

int itemID = 2;

以下哪种方法可以正确,正确地检索项目?

Item item = items.Find(x => x.ItemID == itemID);

Item item items.Where(x => x.ItemID == itemID).FirstOrDefault();

也许这些都不是使用LINQ的最佳解决方案。无论哪种方式,对最佳方法的解释都会有所帮助,因为我经常检索单个业务对象项。何时使用哪个功能也会很棒。谢谢。

3 个答案:

答案 0 :(得分:4)

我不知道Find()Where()之间的实施差异。虽然我怀疑它们是相同的,但我建议坚持使用LINQ扩展方法(Where()Single[OrDefault]()等)而不是特定于您选择的集合实现的方法。因为它们是IEnumerable<T>上的扩展方法,所以如果您愿意,可以更灵活地选择不同的集合实现。

奖励积分:

但是有些事情让我担心 - 你从某个地方加载东西,然后在内存中过滤它们。我更愿意看到类似的东西:

Item item = Item.GetItemForId(2);

将过滤留给(推测)数据库。虽然这可能违反了SRP,但事实上你正在前往:

IRepository<Item> repository = this.itemRepository;
Item item = repository.Get(2);

如果您使用完整的Linq to SQL / Entities,您将能够使用deffered执行并执行以下操作:

Item item = context.Items.SingleOrDefault(i => i.Id == 2);

这不会在调用SingleOrDefault()之前加载所有项目,而是会查看who表达式并为其生成适当的SQL,如:

SELECT [fields] FROM Item WHERE Id = @id

这对我来说都是一个假设,但我确实想明确表示 Linq与实体(实体框架) Linq to SQL ,构建要发送到数据库的SQL语句,而不是 Linq to Objects ,它是相同的方法调用,但是处理内存中的集合对象。

答案 1 :(得分:3)

如果你期望,那么明确更好地使用第二个案例.FirstOrDefault()指定的值可以出现在集合中,并且不是< / strong>特例。

另请注意,Find()List<T>的方法,而Where()扩展名方法,可以应用实现IEnumerable<T>任何类型,因此通过在代码Where()中使用,您可以获得更大的灵活性。

答案 2 :(得分:3)

您应该使用以下内容:

Item item = items.FirstOrDefault(x => x.ItemID == itemID);

根据您希望的工作方式,选择Single,SingleOrDefault,First和FirstOrDefault作为要使用的LINQ方法。如果列表中的多个项与查询匹配,则Single将抛出错误。首先,它将返回遇到的与查询匹配的第一个项。如果没有OrDefault,如果找不到匹配项,它们将抛出错误,在这种情况下它将返回null。这比尝试使用null并获得空引用异常更好。

所以,例如如果您只想处理只有一个项目与ItemID匹配的情况,请使用Single。如果拥有多个匹配并不是无效的,并且您希望优雅地处理不匹配,请使用FirstOrDefault并在使用之前检查结果项是否为空。