LINQ有两种计算可枚举的方法:Count
和LongCount
。实际上,这两者之间的唯一区别是第一个返回int
,而第二个返回long
。
我不清楚为什么添加第二种方法。它似乎唯一的用例是处理超过2B元素的可枚举。这对我来说似乎是一个糟糕的决定,原因如下:
大多数BCL集合都有一维数组支持,这些数组的长度可以保证适合int
。尝试过去会引发OverflowException
/ OutOfMemoryException
。
LongCount
是O(n),因为IEnumerable
是懒惰的。如果你有一个可枚举的3B元素,你可以在其上调用LongCount
,然后再次遍历它(如果你想使用任何值,你将不得不重复),你将添加额外的3B迭代,这将非常缓慢,并将其隐藏在开发人员之外。
由于(1),其他LINQ操作(例如ToArray
/ ToList
)不支持带有2B +元素的可枚举。
我在这里遗漏了什么,或者是否有更实际的原因可以添加LongCount
?感谢。
答案 0 :(得分:4)
我对此设计决定没有第一手资料,但我可以提供有根据的猜测。
该方法对@types/react-router
有明显的用处;查询很容易被庞大的数据库表支持。
我希望
@types/history
产生相同的答案。要求内存中查询使用返回不同类型的不同方法似乎是不正确的,特别是当它很容易实现可枚举版本时。
但就像我说的那样,这是一个有根据的猜测;希望真正从事这种设计工作的人可能会参与进来。
答案 1 :(得分:2)
我很确定它是为数据库查询引入的(例如它应该为sql server查询生成COUNT_BIG而不是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
的结果!
是的,示例有点令人满意,但仍然存在。