添加 LINQ 的 LongCount 扩展方法是否有实际原因?
本文关键字:是否 LINQ LongCount 扩展 方法 添加 | 更新日期: 2023-09-27 18:17:27
LINQ 有 2 种计算枚举量的方法:Count
和 LongCount
。实际上,这两者之间的唯一区别是第一个返回一个int
,而第二个返回一个long
。
我不清楚为什么要添加第二种方法。似乎它唯一的用例是处理超过 2B 元素的枚举。这对我来说似乎是一个糟糕的决定,原因如下:
-
大多数 BCL 集合都由一维数组提供支持,这些数组的长度保证适合
int
。试图过去会引发OverflowException
/OutOfMemoryException
. -
LongCount
是O(n(,因为IEnumerable
是懒惰的。如果你有一个可枚举的 3B 元素,你调用它LongCount
,然后再次迭代它(如果你想使用任何值,你必须这样做(,你将添加一个额外的 3B 迭代,这将非常慢,并且对开发人员隐藏它。 -
其他 LINQ 操作(如
ToArray
/ToList
(不支持具有 2B+ 元素的枚举,因为 (1(。
我在这里错过了什么,还是有更实际的原因添加了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
的结果!
是的,例子有点做作,但仍然如此。