为什么LINQ不缓存枚举?

vrw*_*wim 2 c# linq caching

因此我理解LINQ不会立即执行所有操作,它只是存储信息以获取数据.因此,如果您执行了操作Where,列表中实际上没有任何内容,您只需获得IEnumerable具有成为列表所需信息的信息.

人们可以通过调用将这些信息"折叠"到实际列表中ToList.

现在我想知道,为什么LINQ团队会像这样实现它?List在每个步骤(或a Dictionary)添加一个缓存已经计算过的结果非常容易,所以我猜必须有一个很好的理由.

这可以通过以下代码检查:

var list = Enumerable.Range(1, 10).Where(i => {
    Console.WriteLine("Enumerating: " + i);
    return true;
});

var list2 = list.All(i => {
    return true;
});

var list3 = list.Any(i => {
    return false;
});
Run Code Online (Sandbox Code Playgroud)

如果缓存在那里,它只会Enumerating: i为每个数字输出一次,它将第二次从缓存中获取项目.

编辑:其他问题,为什么LINQ不包含缓存选项?喜欢.Cache()缓存前一个可枚举的结果?

Pat*_*man 6

在每一步添加List非常容易

是的,内存密集.如果数据集总共包含2 GB数据,并且您必须立即将其存储在内存中,该怎么办?如果你迭代它并分批获取它,你就没有很大的内存压力.当您将2 GB序列化为内存时,不要想象如果每个步骤都会这样做会发生什么......

您知道您的代码和您的特定用例,因此只有您作为开发人员才能确定何时将一些迭代拆分到内存是有用的.框架无法知道.

  • 但谁知道呢?构建有效的缓存机制非常困难,尤其是当您不知道它的用例时. (2认同)

小智 6

因为它没有意义,如果你想到所有没有意义的情况,你就不会问它.这不是一个"它有时是否有意义"的问题,因为"有副作用使它变坏".下次评估这样的事情时,请考虑否定因素:

  • 即使不想要,也需要缓存结果,因此内存消耗会增加.
  • 然后在ext运行时,结果可能会有所不同,因为传入的数据可能已更改.您的简单示例(Enumerable.Range)没有问题 - 但过滤客户列表可能会更新它们.

这样的东西很难明智地从开发者那里拿走选择.想要一个缓冲区,做一个(轻松).但副作用会很糟糕.

  • 它有,它被称为`ToList()`,`ToArray()`和`ToDictionary()`@vrwim (3认同)