添加 LINQ 的 LongCount 扩展方法是否有实际原因?

Is there a practical reason why LINQ's LongCount extension method was added?

LINQ 有 2 种计算可枚举数的方法:CountLongCount。实际上,这两者之间的唯一区别是第一个 returns 是 int,而第二个 returns 是 long.

我不清楚为什么要添加第二种方法。似乎它的唯一用例是处理超过 2B 元素的枚举。这对我来说似乎是一个糟糕的决定,原因如下:

  1. 大多数 BCL 集合由一维数组支持,其长度保证适合 int。试图超越它会引发 OverflowException / OutOfMemoryException.

  2. LongCount 是 O(n) 因为 IEnumerable 是惰性的。如果你有一个 3B 元素可枚举,你调用 LongCount 它,然后你再次遍历它(如果你想使用任何值,你将不得不这样做),你将添加额外的 3B 迭代,这将非常慢,并且对开发人员隐藏它。

  3. 其他 LINQ 操作,例如 ToArray / ToList,不支持具有 2B+ 元素的枚举,因为 (1).

我是不是遗漏了什么,还是添加 LongCount 有更实际的原因?谢谢。

我对这个设计决策没有第一手资料,但我可以提供一个有根据的猜测。

该方法对IQueryable有明显的用处;该查询可以很容易地得到一个巨大的数据库 table.

的支持

我希望

IQueryable<Foo> q = whatever;
long result1 = q.LongCount();
long result2 = q.AsEnumerable().LongCount();

产生相同的答案。要求内存中查询使用 returns 不同类型的不同方法似乎有悖常理,尤其是当实现可枚举版本如此容易时。

但正如我所说,这是一个有根据的猜测;希望实际从事此设计的人可以插话。

我很确定它是为数据库查询引入的(例如它应该生成 COUNT_BIG 而不是 sql 服务器查询的 COUNT),但是它 可能 在其他情况下有一些用处。例如假设我有这样的方法:

private static Random _r = new Random(1);
public static IEnumerable<BigInteger> RandomSequence(int upTo)
{
    while (true) {
        var next = _r.Next();
        if (next > upTo)
            yield break;
        yield return next;
    }
}

这个序列没有被任何数组烘焙,也没有在任何地方存储值。因此,它可以轻松生产超过 2B 的物品。现在假设我想检查生成大于 int.MaxValue - 5 的数字需要多少次迭代。如果我这样做:

RandomSequence(int.MaxValue - 5).Count();

它将因溢出异常而失败(因为 Count 方便地在 checked 区域内部包装增量)。但是 LongCount 来拯救!

RandomSequence(int.MaxValue - 5).LongCount();

现在我终于弄明白了,对于种子 1,Random.Next 将在 2583066202 次迭代中产生比 int.MaxValue - 5 更大的结果!

是的,示例有点做作,但仍然如此。