在IEnumerable扩展中 - 为什么只有Count()针对ICollection进行了优化?

时间:2014-10-07 13:12:32

标签: c# performance linq

在对Linq IEnumerable扩展方法进行反编译后,我很高兴看到这一点 在尝试迭代整个可枚举项之前,Count()方法尝试将其向下转换为ICollectionICollection<T>,例如:

    public static int Count<TSource>(this IEnumerable<TSource> source) {

        if (source == null) throw Error.ArgumentNull("source");

        ICollection<TSource> collectionoft = source as ICollection<TSource>;

        if (collectionoft != null) return collectionoft.Count;

        ICollection collection = source as ICollection;

        if (collection != null) return collection.Count;

        int count = 0;

        using (IEnumerator<TSource> e = source.GetEnumerator()) {
            checked {
                while (e.MoveNext()) count++;
            }
        }
        return count;
    }

为什么Any()没有发生这种情况?不会因使用.Count > 0而不是创建数组枚举器而受益吗?

2 个答案:

答案 0 :(得分:5)

并非所有集合都为Count属性提供O(1)访问权限。例如,ConcurrentQueue<T>的访问计数属性是O(n)。因此优化会使情况变得更糟 不应该被称为优化。

不仅ConcurrentQueue<T>,几乎所有并发馆藏(ConcurrentDictionary<TKey,TValue>ConcurrentStack<T>等)都属于此类别

这可能是他们决定不这样做的原因。

答案 1 :(得分:0)

不。代码的成本总是比任何可能的性能提升都要大,这几乎是零。不要忘记LINQ的重点是连接一堆这样的表达式,所以你最有可能使用Any使用谓词,或者使用它自己的束之前的过滤器等。

您使用Any作为Count的替代方案的情况是什么?即使Count优化使用IMO也非常微弱 - 如果您在某些逻辑中执行Count()期望IEnumerable作为参数,那么您可能做错了 - 至少,你倾向于多次枚举可枚举,这很可能会破坏某些东西或者杀死你的表现:D

不要忘记,一旦你在那个可枚举的阵列上做了任何,你就会失去&#34;阵列&#34;,例如categories.Where(i => i.Name.StartsWith("Hello")).Count()使用捷径。

当然,任何空的可枚举的枚举器的成本可能几乎是免费的。枚举器只是一个简单的结构,在数组上,也不会有任何昂贵的初始化。