最终编辑:
我选择了 Timothy 的答案,但如果你想要一个更可爱的实现,可以利用 C# 的 yield 语句,请查看 Eamon 的答案:https://dev59.com/SWIj5IYBdhLWcg3w2ohr#19825659
默认情况下,LINQ 查询是 惰性流式传输的。
ToArray
/ToList
可以提供完全的缓冲,但首先它们是急切的,其次在无限序列中完成可能需要相当长的时间。
有没有一种方法可以同时具有流式传输和缓冲值的组合行为,从而在生成这些元素时即时缓冲,以便后续查询不会触发已经查询过的元素的生成。
这里有一个基本的用例:
static IEnumerable<int> Numbers
{
get
{
int i = -1;
while (true)
{
Console.WriteLine("Generating {0}.", i + 1);
yield return ++i;
}
}
}
static void Main(string[] args)
{
IEnumerable<int> evenNumbers = Numbers.Where(i => i % 2 == 0);
foreach (int n in evenNumbers)
{
Console.WriteLine("Reading {0}.", n);
if (n == 10) break;
}
Console.WriteLine("==========");
foreach (int n in evenNumbers)
{
Console.WriteLine("Reading {0}.", n);
if (n == 10) break;
}
}
这里是输出结果:
Generating 0.
Reading 0.
Generating 1.
Generating 2.
Reading 2.
Generating 3.
Generating 4.
Reading 4.
Generating 5.
Generating 6.
Reading 6.
Generating 7.
Generating 8.
Reading 8.
Generating 9.
Generating 10.
Reading 10.
==========
Generating 0.
Reading 0.
Generating 1.
Generating 2.
Reading 2.
Generating 3.
Generating 4.
Reading 4.
Generating 5.
Generating 6.
Reading 6.
Generating 7.
Generating 8.
Reading 8.
Generating 9.
Generating 10.
Reading 10.
生成代码被触发了22次。
我希望它在可枚举对象第一次迭代时只被触发11次。
然后第二次迭代将受益于已经生成的值。
大概是这样的:
IEnumerable<int> evenNumbers = Numbers.Where(i => i % 2 == 0).Buffer();
对于熟悉Rx的人来说,它类似于ReplaySubject
的行为。
IEnumerable
,已经有一些在互联网上的例子。 - Scott Chamberlain