2009-10-30 3 views
2

Count 속성 (예 : List<T>)이있는 IEnumerable<T>에서 LINQ Count() 확장 메서드가 호출되면 Count() 메서드는 해당 속성을 찾고 반환합니다 (열거하여 항목을 계산하는 것이 아니라).C# 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<T>를 구현하는 사용자 지정 컬렉션에서 CLR Count() 확장 메서드를 사용할 수있는 방식으로 IEnumerable<T> 속성을 노출 할 수있는 방법은 무엇입니까? 그것의 이점?

답변

11

이름으로 Count 속성을 찾지 않지만 ICollection<T>을 구현하는지 확인한 다음 해당 형식의 Count 속성을 사용합니다. documentation에서 :

소스의 종류 구현 요소의 수를 얻기 위해 사용되는, ICollection<T>를 구현하는 경우. 그렇지 않으면이 메서드가 개수를 결정합니다.

는 (물론 이것은 단지 술어을지지 않습니다 과부하에 적용됩니다.)

을 그래서, 당신은, 효율적으로 수를 얻을 당신이 ICollection<T>를 구현하고 있는지 확인하려면.

5

예, Enumerable.Count 메서드는 실제로 ICollection<T>을 찾고 Count 속성을 사용할 경우이를 사용합니다. Reflector에서 Enumerable.Count를 보면이를 확인할 수 있습니다.

추가 매개 변수가없는 Count 확장 방법을 사용하는 경우에만 해당됩니다. 술어를 사용하는 버전을 사용하면 열거 가능한 요소를 처리하게됩니다.