使用Skip和Take的LINQ

26
我使用了以下代码从 IEnumerable 中取出一些项目,但它总是将源返回为 null,并且计数为 0,实际上在 IEnumerable 中存在项目。

我使用了以下代码从 IEnumerable 中取出一些项目,但它总是将源返回为 null,并且计数为 0,实际上在 IEnumerable 中存在项目。

private void GetItemsPrice(IEnumerable<Item> items, int customerNumber)
{
    var a = items.Skip(2).Take(5);
}

当我尝试访问a时,它的计数为0。这里有什么问题吗?

输入图像描述


4
这个收藏品最初有多少件物品? - Grant Thomas
1
“返回空源”是什么意思?如果a.Count()返回0,那么items中最多只有2个元素。如果您认为有102个项目,则我怀疑您的诊断不正确。 - Jon Skeet
@JonSkeet,请检查我的附件,它是从即时窗口中获取的。 - user1618825
1
你似乎仍未枚举你的集合。IEnumrables是惰性加载的,除非你告诉它们该做什么,否则它们不会按照你的意愿执行。 - Thomas Lindvall
2
@SSS:从截图中没有显示出 items.Count() 大于2的迹象。 - Jon Skeet
显示剩余8条评论
1个回答

42

请记住,在您的代码中,变量a本身就是一个查询。它不是查询执行的结果。当您使用立即窗口观察查询(实际上这涉及到具有延迟执行的查询,否则您将获得查询结果而不是查询),它将始终显示

{System.Linq.Enumerable.TakeIterator<int>}
    count: 0
    source: null

您可以使用以下代码进行验证,该代码显然具有足够的项目:

int[] items = { 1, 2, 3, 4, 5, 6, 7 };
var a = items.Skip(2).Take(3);

因此,您应该执行查询以查看查询执行结果。在立即窗口中编写:

所以,你应该执行你的查询来查看查询执行结果。在立即窗口中写入:

a.ToList()

您将会看到查询执行的结果:

Count = 3
    [0]: 3
    [1]: 4
    [2]: 5

2
该方法的立即返回值是一个对象,它存储执行操作所需的所有信息。此方法表示的查询直到通过直接调用其GetEnumerator方法或使用foreach枚举对象才会执行。 - Xaruth
@Xaruth 是的,这就是所谓的“查询”:一个存储执行操作所需的所有信息的对象。 - Sergey Berezovskiy
谢谢澄清。我需要将items.Skip(2).Take(5)作为参数传递给另一个方法。我需要使用.ToList()将其作为参数传递吗? - user1618825
1
正如我在另一条评论中所指出的:这就是为什么你不应该使用调试器来显示你不知道含义的字段,然后假设你已经理解了它们的含义... - Jon Skeet
1
@SSS:嗯,你可能想这么做。但这取决于情况。但你需要明白,你看到0的唯一原因是因为你正在查看一个实现细节,你通常无法观察到它。这不是序列的长度。 - Jon Skeet
正如Jon所说,这取决于情况。如果你返回a,那么查询将由调用者稍后执行(这并不总是可能的)。如果你通过添加ToList()返回查询执行结果,那么调用者将在内存中处理对象(如果你的查询从数据库获取项目,则可能会出现问题)。 - Sergey Berezovskiy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接