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

本文关键字:是否 LINQ LongCount 扩展 方法 添加 | 更新日期: 2023-09-27 18:17:27

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

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

  1. 大多数 BCL 集合都由一维数组提供支持,这些数组的长度保证适合int。试图过去会引发OverflowException/OutOfMemoryException.

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

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

我在这里错过了什么,还是有更实际的原因添加了LongCount?谢谢。

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

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

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

我期待

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

以产生相同的答案。要求内存中查询使用返回不同类型的不同方法似乎是不正常的,尤其是在实现可枚举版本非常容易的情况下。

但就像我说的,这是一个有根据的猜测;希望真正参与这个设计的人可能会插话。

我很确定它是为数据库查询引入的(例如,它应该生成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 的结果!

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