IEnumerableとIEnumeratorを使用していましたが、1つのポイントを明確に取得できませんでした。foreachがある場合、なぜこの2つのインターフェイスが必要なのですか?インターフェイスを使用する必要があるシナリオはありますか?はいの場合、誰かが例を挙げて説明できますか?任意の提案や意見を歓迎します。ありがとう。
3 に答える
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>
カーソルとして考えてください。テーブルに新しいカーソルを指定するように依頼できます。また、同じテーブル上に同時に複数のカーソルを置くことができます。
この違いを実際に理解するには時間がかかる場合がありますが、リスト(または配列など)には「リストのどこにいるか」という概念はなく、そのリスト/配列/その他の機能を反復処理することを覚えておいてください。その少しの状態が役に立ちます。
ジョンが言ったこと。
IEnumerable
またはIEnumerable<T>
:これを実装することにより、オブジェクトは、シーケンス/コレクション/セットをトラバースするために使用できるイテレータを提供できることを示しますIEnumerator
またはIEnumerator<T>
:前のインターフェースで定義されたGetEnumeratorメソッドを呼び出すと、IEnumerator参照としてイテレーターオブジェクトを取得します。これにより、MoveNext()を呼び出して、Currentオブジェクトを取得できます。foreach
:は、内部でどのように機能するかを知る必要がないという意味で、C#の構成/ファサードです。内部的にイテレータを取得し、適切なメソッドを呼び出して、各アイテム(foreachブロックのコンテンツ)で実行したいことに集中します。ほとんどの場合、独自のタイプまたはカスタムイテレーションを実装している場合を除き、foreachが必要です。実装している場合は、最初の2つのインターフェイスを理解する必要があります。
foreach --IIRCを使用するためにIEnumeratorとそのバリアントを実装する必要はないことに注意してください。必要なのは、boolを返すMoveNext()メソッドを持つオブジェクトを返すGetEnumerator()メソッドと、オブジェクト。IEnumeratorとIEnumerableを使用する必要はありませんが、通常は使用することをお勧めします。詳細については、こちらをご覧ください。