2009-10-30 101 views
2

如果LINQ Count()扩展方法上IEnumerable<T>具有Count属性调用(如List<T>),请问Count()方法来查找该财产,并将其返回(而不是通过枚举计数的项目他们)?下面的测试代码似乎表明,它的作用:C#伯爵()扩展方法性能

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>自定义集合公开自己的Count财产以这样的方式在CLR Count()扩展方法可以采取它的优点?

回答

11

它不按名称查找Count属性,但它会检查它是否实现ICollection<T>,然后使用该类型的Count属性。从documentation

如果源的类型实现 ICollection<T>,即 实现用于获得元件的 计数。否则,此方法确定计数。

如果要有效地得到计数,确保实现ICollection<T>(显然,这仅适用于不带谓词过载。)

所以,。

5

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

如果您使用Count扩展方法这需要任何附加参数这是唯一真正虽然。如果使用带谓词的版本,它将遍历可枚举元素。