为什么LINQ不缓存枚举?

时间:2016-05-25 12:57:32

标签: c# linq caching

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

可以通过调用ToList将此信息“折叠”到实际列表中。

现在我想知道,为什么LINQ团队会这样实现呢?在每一步(或List)添加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;
});

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

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

2 个答案:

答案 0 :(得分:6)

  

在每一步添加一个List非常容易

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

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

答案 1 :(得分:6)

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

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

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