为什么添加LINQ的LongCount扩展方法有一个实际的原因吗?

时间:2016-11-11 22:10:43

标签: c# .net linq ienumerable linq-to-objects

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

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

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

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

  3. 由于(1),其他LINQ操作(例如ToArray / ToList)不支持带有2B +元素的可枚举。

  4. 我在这里遗漏了什么,或者是否有更实际的原因可以添加LongCount?感谢。

2 个答案:

答案 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的结果!

是的,示例有点令人满意,但仍然存在。