假设我有以下项目清单:
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的最佳解决方案。无论哪种方式,对最佳方法的解释都会有所帮助,因为我经常检索单个业务对象项。何时使用哪个功能也会很棒。谢谢。
答案 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并在使用之前检查结果项是否为空。