代码之家  ›  专栏  ›  技术社区  ›  Joseph Sturtevant

c count()扩展方法性能

  •  2
  • Joseph Sturtevant  · 技术社区  · 15 年前

    如果LINQ Count() 在上调用扩展方法 IEnumerable<T> 那有 Count 财产(例如) List<T> ) 计数() 方法查找该属性并返回它(而不是通过枚举它们来计算项)?以下测试代码似乎表明它确实存在:

    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(); }
        }
    }
    

    相关说明: 如何实现自定义集合 IEnumerable<t> 暴露自己 伯爵 以这样的方式使clr 计数() 扩展方法可以利用它吗?

    2 回复  |  直到 15 年前
        1
  •  12
  •   Jon Skeet    15 年前

    它找不到 Count 属性,但它检查是否实现 ICollection<T> ,然后使用该类型的 伯爵 财产。从 documentation 以下内容:

    如果源类型实现 i收集<t> ,那 实现用于获取 元素计数。否则,这个 方法确定计数。

    (显然,这只适用于不带谓词的重载。)

    因此,如果要有效地获取计数,请确保实现 i收集<t> .

        2
  •  5
  •   JaredPar    15 年前

    是的,Enumerable.Count方法确实会查找 ICollection<T> 如果找到,使用它的Count属性。您可以通过查看Reflector中的Enumerable.Count来验证这一点。

    但只有在使用不带其他参数的Count扩展方法时,这才是正确的。如果使用带谓词的版本,它将遍历可枚举元素。