C# Count() Extension Method Performance

拥有回忆 提交于 2019-11-28 09:31:50

问题


If the LINQ Count() extension method is invoked on an IEnumerable<T> that has a Count property (e.g. List<T>), does the Count() method look for that property and return it (rather than counting the items by enumerating them)? The following test code seems to indicate that it does:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

namespace CountSpeedTest
{
    // Output:
    // List      - CLR : 0 ms
    // Enumerate - CLR : 10 ms
    // List      - Mine: 12 ms
    // Enumerate - Mine: 12 ms
    class Program
    {
        private const int Runs = 10;
        private const int Items = 1000000;

        static void Main(string[] args)
        {
            var total = new long[] {0, 0, 0, 0};
            for (int i = 0; i < Runs; ++i)
            {
                var items = Enumerable.Range(0, Items).Select(o => o.ToString()).ToList();
                var list = new List<string>(items);
                var enumerate = new Enumerate<string>(items);
                total[0] += TimeCount(list, c => c.Count());
                total[1] += TimeCount(enumerate, c => c.Count());
                total[2] += TimeCount(list, c => c.SlowCount());
                total[3] += TimeCount(enumerate, c => c.SlowCount());
            }
            Console.WriteLine(String.Format("List      - CLR : {0} ms", total[0] / Runs));
            Console.WriteLine(String.Format("Enumerate - CLR : {0} ms", total[1] / Runs));
            Console.WriteLine(String.Format("List      - Mine: {0} ms", total[2] / Runs));
            Console.WriteLine(String.Format("Enumerate - Mine: {0} ms", total[3] / Runs));
            Console.ReadKey(true);
        }

        private static long TimeCount<T>(IEnumerable<T> collection, Func<IEnumerable<T>, int> counter)
        {
            var stopwatch = Stopwatch.StartNew();
            var count = counter(collection);
            stopwatch.Stop();
            if (count != Items) throw new Exception("Incorrect Count");
            return stopwatch.ElapsedMilliseconds;
        }
    }

    public static class CountExtensions
    {
        // Performs a simple enumeration based count.
        public static int SlowCount<T>(this IEnumerable<T> items)
        {
            var i = 0;
            var enumerator = items.GetEnumerator();
            while (enumerator.MoveNext()) i++;
            return i;
        }
    }

    // Wraps an IEnumerable<T> to hide its Count property.
    public class Enumerate<T> : IEnumerable<T>
    {
        private readonly IEnumerable<T> collection;
        public Enumerate(IEnumerable<T> collection) { this.collection = collection; }

        public IEnumerator<T> GetEnumerator() { return collection.GetEnumerator(); }
        IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
    }
}

On a related note: how can a custom collection which implements IEnumerable<T> expose its own Count property in such a way that the CLR Count() extension method can take advantage of it?


回答1:


It doesn't look for a Count property by name, but it does check whether it implements ICollection<T>, and then uses that type's Count property. From the documentation:

If the type of source implements ICollection<T>, that implementation is used to obtain the count of elements. Otherwise, this method determines the count.

(Obviously this only applies to the overload which doesn't take a predicate.)

So, if you want to obtain the count efficiently, make sure you implement ICollection<T>.




回答2:


Yes, the Enumerable.Count method will indeed look for ICollection<T> and use it's Count property if found. You can verify this by looking at Enumerable.Count in reflector.

This is only true though if you use the Count extension method which takes no additional parameters. If you use the version which takes a predicate it will walk the enumerable elements.



来源:https://stackoverflow.com/questions/1651301/c-sharp-count-extension-method-performance

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!