26

IEnumerableとIEnumeratorを使用していましたが、1つのポイントを明確に取得できませんでした。foreachがある場合、なぜこの2つのインターフェイスが必要なのですか?インターフェイスを使用する必要があるシナリオはありますか?はいの場合、誰かが例を挙げて説明できますか?任意の提案や意見を歓迎します。ありがとう。

4

3 に答える 3

57

foreach 多くの場合、インターフェースを使用します。使用できるシーケンスを実装する場合は、インターフェイスが必要ですforeach。(ただし、イテレーターブロックは通常、この実装タスクを非常に単純にします。)

ただし、イテレータを直接使用すると便利な場合があります良い例は、2つの異なるシーケンスを「ペアリング」しようとする場合です。たとえば、名前と年齢の2つのシーケンスを受け取り、2つを一緒に印刷するとします。あなたは書くかもしれません:

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");
        }

    }
}

同様に、最初の項目を残りの項目とは異なる方法で処理する(たとえば)場合は、イテレータを使用すると便利です。

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;
    }
}

ここで、との違いに興味がある場合はIEnumerator<T>IEnumerable<T>データベースの用語で考えてみてください。IEnumerable<T>テーブルとして、そしてIEnumerator<T>カーソルとして考えてください。テーブルに新しいカーソルを指定するように依頼できます。また、同じテーブル上に同時に複数のカーソルを置くことができます。

この違いを実際に理解するには時間がかかる場合がありますが、リスト(または配列など)には「リストのどこにいるか」という概念はなく、そのリスト/配列/その他の機能を反復処理することを覚えておいてくださいその少しの状態が役に立ちます。

于 2009-07-06T06:15:46.080 に答える
9

ジョンが言ったこと。

  • IEnumerableまたはIEnumerable<T>:これを実装することにより、オブジェクトは、シーケンス/コレクション/セットをトラバースするために使用できるイテレータを提供できることを示します
  • IEnumeratorまたはIEnumerator<T>:前のインターフェースで定義されたGetEnumeratorメソッドを呼び出すと、IEnumerator参照としてイテレーターオブジェクトを取得します。これにより、MoveNext()を呼び出して、Currentオブジェクトを取得できます。
  • foreach:は、内部でどのように機能するかを知る必要がないという意味で、C#の構成/ファサードです。内部的にイテレータを取得し、適切なメソッドを呼び出して、各アイテム(foreachブロックのコンテンツ)で実行したいことに集中します。ほとんどの場合、独自のタイプまたはカスタムイテレーションを実装している場合を除き、foreachが必要です。実装している場合は、最初の2つのインターフェイスを理解する必要があります。
于 2009-07-06T06:54:26.910 に答える
7

foreach --IIRCを使用するためにIEnumeratorとそのバリアントを実装する必要はないことに注意してください。必要なのは、boolを返すMoveNext()メソッドを持つオブジェクトを返すGetEnumerator()メソッドと、オブジェクト。IEnumeratorとIEnumerableを使用する必要はありませんが、通常は使用することをお勧めします。詳細については、こちらをご覧ください。

于 2009-07-06T09:47:44.577 に答える