正如其他人指出的那样,您提供的代码只会迭代列表中的项目一次。
但是,这只会为您提供一页的项目。如果您要处理多个页面,则必须为每个页面调用一次该代码(因为您必须在某处递增 currentPage,对吧?)。
我的意思是你必须做这样的事情:
for (int currentPage = 0; currentPage < numPages; ++currentPage)
{
foreach (var item in items.Skip(currentPage*itemsPerPage).Take(itemsPerPage))
{
//Do stuff
}
}
现在如果你这样做那个,那么你将重复序列多次 - 每个页面一次。第一次迭代只会到第一页的结尾,但下一次将从第二页的开头迭代到结尾(通过Skip() 和Take()) - 下一次将从第三页的开头到结尾。以此类推。
为避免这种情况,您可以为IEnumerable<T> 编写一个扩展方法,将数据分成批次(您也可以将其描述为将数据“分页”成“页面”)。
而不是仅仅呈现 IEnumerable 的 IEnumerable,将每个批次包装在一个类中以提供批次索引以及批次中的项目会更有用,如下所示:
public sealed class Batch<T>
{
public readonly int Index;
public readonly IEnumerable<T> Items;
public Batch(int index, IEnumerable<T> items)
{
Index = index;
Items = items;
}
}
public static class EnumerableExt
{
// Note: Not threadsafe, so not suitable for use with Parallel.Foreach() or IEnumerable.AsParallel()
public static IEnumerable<Batch<T>> Partition<T>(this IEnumerable<T> input, int batchSize)
{
var enumerator = input.GetEnumerator();
int index = 0;
while (enumerator.MoveNext())
yield return new Batch<T>(index++, nextBatch(enumerator, batchSize));
}
private static IEnumerable<T> nextBatch<T>(IEnumerator<T> enumerator, int blockSize)
{
do { yield return enumerator.Current; }
while (--blockSize > 0 && enumerator.MoveNext());
}
}
这个扩展方法不缓存数据,只遍历一次。
使用这种扩展方法,批量处理项目变得更具可读性。请注意,此示例枚举所有页面的所有项目,这与 OP 的示例不同,它仅遍历一页的项目:
var items = Enumerable.Range(10, 50); // Pretend we have 50 items.
int itemsPerPage = 20;
foreach (var page in items.Partition(itemsPerPage))
{
Console.Write("Page " + page.Index + " items: ");
foreach (var i in page.Items)
Console.Write(i + " ");
Console.WriteLine();
}