2009-10-30 106 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擴展方法這需要任何附加參數這是唯一真正雖然。如果使用帶謂詞的版本,它將遍歷可枚舉元素。