2017-11-09 6 views
1

IEnumerableについて.ToList()を実行すると、サイズが先行することがわからないため、リストはIEnumerableをスキャン中に潜在的に再割り当てされる可能性があります。サイズが分かっている場合は、パフォーマンス上の不利益を回避する簡単な方法はありますか? Listを必要な容量で初期化してからIEnumerableをコピーすると何か問題が発生しますか?理想的には、.ToList(capacity)(これは存在しません)という単純なものです。容量をリストするには?

+1

を 'ToList'がちょうど'一覧(IEnumerableをを呼び出します) 'コンストラクタで、ソースが' ICollection 'を実装しているかどうかをチェックし、カウントを使用して容量を設定します。 – Lee

答えて

3

容量がIEnumerable<T>の一部であり、それがICollection<T>でもある場合、ライブラリは正しい容量で割り当てます。ここで

あなたはToList()を呼び出すときに呼び出されるreference implementation of List<T>(IEnumerable<T> source)、次のとおりです。

public List(IEnumerable<T> collection) { 
    if (collection==null) 
     ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection); 
    Contract.EndContractBlock(); 

    ICollection<T> c = collection as ICollection<T>; 
    if(c != null) { 
     int count = c.Count; 
     if (count == 0) { 
      _items = _emptyArray; 
     } else { 
      _items = new T[count]; 
      c.CopyTo(_items, 0); 
      _size = count; 
     } 
    } else {     
     _size = 0; 
     _items = _emptyArray; 
     // This enumerable could be empty. Let Add allocate a new array, if needed. 
     // Note it will also go to _defaultCapacity first, not 1, then 2, etc. 

     using(IEnumerator<T> en = collection.GetEnumerator()) { 
      while(en.MoveNext()) { 
       Add(en.Current);          
      } 
     } 
    } 
} 

collectionICollection<T>を実装したときに、コンストラクタがどのように動作するか:むしろ内容を反復し、各項目のAddを呼ぶよりも、それは内部を割り当て_items配列を作成し、再割り当てなしでコンテンツをコピーします。

容量が IEnumerable<T>を実装したクラスに埋め込まれ ないあるとき、あなたは簡単に標準的な方法の組み合わせを使用して、1を自分で定義することができる状況では

static class ToListExtension { 
    public static List<T> ToList(this IEnumerable<T> source, int capacity) { 
     var res = new List<T>(capacity); 
     res.AddRange(source); 
     return res; 
    } 
} 
関連する問題