2011-01-07 9 views
7

dと指定すると、リストや配列などの固定されたシーケンス、いくつかの外部データソースを列挙するAST、または既存のコレクションのASTさえ扱うことができます。 foreach、countなどの列挙操作で毎回ASTが実行されないように、列挙可能体を安全に「実現」する方法はありますか?IEnumerableを暗記またはマテリアライズする方法はありますか?

私はこの表現を作成するのに多くの場合.ToArray()を使用しましたが、基本ストレージがすでにリストやその他の固定シーケンスである場合は、無駄なコピーと思われます。私は.Any()foreachは二回、それがunccessarily列挙をコピーせずにシーケンスを列挙しようとすることを心配することなく

var enumerable = someEnumerable.Materialize(); 

if(enumberable.Any() { 
    foreach(var item in enumerable) { 
    ... 
    } 
} else { 
    ... 
} 

を行うことができればいいだろう。

+1

これはいいアイデアですが、既存のコレクションへの変異から保護するために、しばしばexistingCollection.ToListが行われることを指摘します。 – Ani

+0

.ToList()の問題は、リスト(配列、ICollectionsなど)ではなく、変更可能なコレクションを返す列挙型のリストを作成することです。 –

答えて

6

十分に簡単:

ちょうど少し良く私によるとトーマスの答えと同じ
public static IList<TSource> Materialize<TSource>(this IEnumerable<TSource> source) 
{ 
    if (source is IList<TSource>) 
    { 
     // Already a list, use it as is 
     return (IList<TSource>)source; 
    } 
    else 
    { 
     // Not a list, materialize it to a list 
     return source.ToList(); 
    } 
} 
+3

これは良いアプローチです。私は代わりに 'IEnumerable 'を返し、 'ICollection'と' ICollection 'もチェックする方が良いと思います。 – Ani

+4

これは、新しいコピーを常に返すように見えるLinq.ToList()実装とは微妙に異なります。結果を変更しても元のものは変更されません。書かれた意志としてマテリアライズすると、入力の種類によってはコピーを返すこともあり、時には元のものを返すこともあるので、結果を変更するとオリジナルが変更されることがあります。 – Handcraftsman

+0

アニ氏は正しいアイデアを得ました。私の意図は、変更可能なリストを作成することではなく、複数回列挙するのが安全で効率的なIEnumerable です。また、私はそれをテストしたことはありませんが、私はToArray()がより安価なフォールバックマテライザーであると仮定します。 –

2

は、私が数年前に書いたこのブログの記事をチェックアウト:それはhttp://www.fallingcanbedeadly.com/posts/crazy-extention-methods-tolazylist/

を、私は効果的にあなたが探しているものんToLazyListと呼ばれるメソッドを定義します。

IListのインスタンスがLazyListにラップされないように調整することはできますが、最終的には入力シーケンスの完全コピーを作成しますが、これはこれが起こらないようにします(ただし、あなたが得たIListがすでに効果的にメモされているという前提を持ちます)。

+1

これは本当に興味深い拡張ですが、私はそれがOPが望んでいるものに関連しているとは思いません。これは、必要に応じてシーケンスの実体化を遅らせる一方で、OPは効率的な方法でシーケンスを熱心に実現することを望んでいる。必要に応じて既存のコレクションへの参照を取得します。 – Ani

+0

あなたのブログに何かが壊れているようです。この投稿にあったURLには、サイトルートにリダイレクトされた 'www'がありません –

6

public static ICollection<T> Materialize<T>(this IEnumerable<T> source) 
{ 
    if (source == null) 
     return null; 

    return source as ICollection<T> ?? source.ToList(); 
} 

これはその有効なコレクション場合は、既存のコレクション自体を返すために傾向があることに注意してくださいそれ以外の場合は新しいコレクションを生成します。 2つは微妙に異なっていますが、それは問題ではないと思います。

関連する問題