【问题标题】:C# Count() Extension Method PerformanceC# Count() 扩展方法性能
【发布时间】:2009-10-31 01:43:03
【问题描述】:

如果在具有Count 属性(例如List<T>)的IEnumerable<T> 上调用 LINQ Count() 扩展方法,Count() 方法是否会查找该属性并返回它(而不是计算通过枚举项目)?以下测试代码似乎表明确实如此:

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&lt;T&gt; 的自定义集合如何以CLR Count() 扩展方法可以利用它的方式公开其自己的Count 属性?

【问题讨论】:

    标签: c# linq count extension-methods


    【解决方案1】:

    它不会按名称查找Count 属性,但会检查它是否实现ICollection&lt;T&gt;,然后使用该类型的Count 属性。来自documentation

    如果源的类型实现 ICollection&lt;T&gt;,那个 实现用于获得 元素的数量。否则,这 方法确定计数。

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

    因此,如果您想有效地获取计数,请确保实现ICollection&lt;T&gt;

    【讨论】:

      【解决方案2】:

      是的,Enumerable.Count 方法确实会寻找ICollection&lt;T&gt; 并在找到时使用它的 Count 属性。您可以通过查看反射器中的 Enumerable.Count 来验证这一点。

      这只有在您使用不带附加参数的 Count 扩展方法时才成立。如果您使用带有谓词的版本,它将遍历可枚举元素。

      【讨论】:

        猜你喜欢
        • 2010-11-03
        • 2011-02-05
        • 1970-01-01
        • 2015-09-01
        • 2010-09-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多