2009-07-06 11 views
22

私はIEnumerableとIEnumeratorを経由していましたが、明確に1つのポイントを取得できませんでした。foreachがある場合、なぜこの2つのインターフェイスが必要ですか?インターフェイスを使用しなければならないシナリオはありますか?はいの場合、例を挙げて説明することができます。 ご意見、ご感想は大歓迎です。おかげさまで IEnumerable、IEnumeratorとforeach、いつ使用するか

答えて

46

foreachは、多くの場合、インターフェイスをにします。 の文字列を実装したい場合は、foreachのインタフェースを使用する必要があります。 (イテレータブロックは通常、この実装タスクを非常に簡単にします)。

ただし、ちょうどイテレータを直接使用すると便利です。良い例は、2つの異なるシーケンスを「ペアにする」ときです。たとえば、名前の1つと年代の2つのシーケンスを受信し、2つのシーケンスを一緒に印刷するとします。あなたは書くかもしれません:あなたの場合は、今すぐ

public T Max<T>(IEnumerable<T> items) 
{ 
    Comparer<T> comparer = Comparer<T>.Default; 

    using (IEnumerator<T> iterator = items.GetEnumerator()) 
    { 
     if (!iterator.MoveNext()) 
     { 
      throw new InvalidOperationException("No elements"); 
     } 
     T currentMax = iterator.Current; 

     // Now we've got an initial value, loop over the rest 
     while (iterator.MoveNext()) 
     { 
      T candidate = iterator.Current; 
      if (comparer.Compare(candidate, currentMax) > 0) 
      { 
       currentMax = candidate; 
      } 
     } 
     return currentMax; 
    } 
} 

static void PrintNamesAndAges(IEnumerable<string> names, IEnumerable<int> ages) 
{ 
    using (IEnumerator<int> ageIterator = ages.GetEnumerator()) 
    { 
     foreach (string name in names) 
     { 
      if (!ageIterator.MoveNext()) 
      { 
       throw new ArgumentException("Not enough ages"); 
      } 
      Console.WriteLine("{0} is {1} years old", name, ageIterator.Current); 
     } 
     if (ageIterator.MoveNext()) 
     { 
      throw new ArgumentException("Not enough names"); 
     } 

    } 
} 

は、同様に、あなたが(たとえば)扱いたい場合は残りの部分に異なった最初の項目をイテレータを使用することが有用であり得ますIEnumerator<T>IEnumerable<T>の違いに興味があるなら、テーブルとしてIEnumerable<T>と考えると、カーソルとしてIEnumerator<T>と考えることができます。テーブルに新しいカーソルを与えるように頼むことができます。また、同時に同じテーブルに複数のカーソルを置くこともできます。

この相違点は本当にありがたいですが、リスト(または配列など)に「リストにある場所」という概念はありませんが、そのリスト/ array/whatever のビットがあると便利です。

+0

ありがとうございました。私は今それを得て、それを明確にするためにもっと研究します。 また、次のリンクは非常に便利です: http://stackoverflow.com/questions/558304/can-anyone-explain-ienumerable-and-ienumerator-to-me – Wondering

+0

これはIEnumeratorを使用して立ち往生した場所の例です効率を維持する。 http://stackoverflow.com/questions/1018407/what-is-the-most-elegant-way-to-get-a-set-of-items-by-index-from-a-collection/1025137#1025137 –

+0

@ジョンスキート私はあなたがコード化した方法を本当に好きでしたメソッド。私は1つの質問があります。 IEnumberatorでconstructを使用しています。私は使用することがそれの中に来るものを処分することを知っている()。なぜあなたはIEnumberatorでそれを使いましたか? –

8

ジョンが言ったこと。

  • IEnumerableまたはIEnumerable<T>:オブジェクトは、それはあなたがシーケンス/コレクションを超えるトラバースするために使用することができますイテレータを与えることができると述べて、これを実装することによって/
  • IEnumeratorまたはIEnumerator<T>を設定します。あなたが定義されたGetEnumeratorメソッドを呼び出す場合前のインタフェースでは、イテレータオブジェクトをIEnumerator参照として取得します。これにより、MoveNext()を呼び出してCurrentオブジェクトを取得することができます。
  • foreach:それはフードの下でどのように動作するかを知る必要がないという意味で、C#の構造/ファサードです。内部的にイテレータを取得し、各アイテム(foreachブロックの内容)で何をしたいかに集中するための正しいメソッドを呼び出します。ほとんどの場合、独自のタイプまたはカスタム反復を実装している場合を除いて、foreachが必要になります。その場合は、最初の2つのインタフェースを知る必要があります。それが必要とするすべてのMoveNextメソッド()メソッドが返すたオブジェクトを返すGetEnumeratorメソッド()メソッドで、IIRCを - あなたははforeachのを使用するために、そののIEnumeratorとvarientsを実装するを持っていない心の中で
+0

私にもっと分かりやすくしてくれたGishuに感謝します。 また、このリンクは非常に便利です: http://stackoverflow.com/questions/558304/can-anyone-explain-ienumerable-and-ienumerator-to-me – Wondering

6

ベアbool、およびオブジェクトを返すCurrentプロパティ。 IEnumeratorとIEnumerableは使用する必要はありませんが、一般的にIEnumeratorとIEnumerableを使用するのは非常に良い考えです。詳細については、hereを参照してください。

+0

これは奇妙な古い獣です2つのメソッドを実装するだけです。これを行う際の大きな問題は、タイプシステムがそのオブジェクトが列挙可能であることを知らないことです。オブジェクトにLinqを使用することで問題が発生すると思います。 –

+3

はい、それは奇妙です。その機能をサポートする理由は、C#1.0で整数のコレクションを記述し、ボクシングなしでそれらを列挙できるようにするためです。 IE が完成したので、もう「パターン」アプローチは必要ありません。 –

+1

@Eric Lippert:GetEnumeratorメソッドが構造体を返すクラスには、クラスを返すIEnumerable.GetEnumeratorメソッドが必要であることを示唆していますが、構造体列挙子のヒープ割り当てを避けることができます。 – supercat

関連する問題