質問
(IEnumerable Returns GetEnumerator() とは別に、「foreach」には IEnumerble が必須です)
ほぼ次の 2 つのアプローチにより、コレクションを反復処理できます。
お互いの利点は何ですか?(私はIENUMERABLEとIENUMERATORの違いを尋ねていません)。
static void Main()
{
IEnumerator<int> em = MyEnumerator<int>(new int[] { 1, 2, 3, 4 });
IEnumerator<int> e = Collection<int>
(new int[] { 1, 2, 3, 4 }).GetEnumerator();
while (em.MoveNext())
{
Console.WriteLine(em.Current);
}
while (e.MoveNext())
{
Console.WriteLine(e.Current);
}
Console.ReadKey(true);
}
アプローチ1
public static IEnumerator<T> MyEnumerator<T>(T[] vals )
{
T[] some = vals;
foreach (var v in some)
{
yield return v;
}
}
アプローチ2
public static IEnumerable<T> Collection<T>(T[] vals)
{
T[] some = vals;
foreach (var v in some)
{
yield return v;
}
}
解決
主な違いは、ほとんどの API が次の入力をサポートしていることです。 IEnumerable<T>
しかし、そうではありません IEnumerator<T>
.
また、構文は次のとおりです。Reset() を使用する場合は、必ず Reset() を呼び出す必要があります。 IEnumerable<T>
(ただ電話してください GetEnumerator
また)。リセットは悪い考えであるという Eric Lipper のコメントも参照してください。リセットが実装されていない場合 IEnumerator<T>
または、バグがあり、1 回限りの列挙子になります (多くの場合、まったく役に立ちません)。
もう 1 つの違いは、 IEnumerable<T>
同時に複数のスレッドから列挙できますが、 IEnumerator<T>
列挙されたデータに 1 つの位置を保存します ( RandomEnumerable
または RangeEnumerable
).
したがって、結論は次のとおりです IEnumerable<T>
の方が汎用性が高くなりますが、とにかく、 IEnumerator<T>
を生成する IEnumerable<T>
その辺はシンプルです。
class EnumeratorWrapper<T> : IEnumerable<T>
{
Func<IEnumerator<T>> m_generator;
public EnumeratorWrapper(Func<IEnumerator<T>> generator)
{
m_generator = generator;
}
public IEnumerator<T> GetEnumerator()
{
return m_generator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return m_generator();
}
}
API の一貫性のためにのみ使用 IEnumerable<T>
私にとって最良の解決策のように思えます。
しかし、問題は Reset()
で IEnumerator<T>
いずれにせよ、それは使用不可能なソリューションになりますので、 IEnumerable<T>
が進むべき道です。
他のヒント
私が間違っているが、IEnumerableとIEnumeratorの違いだけが正しければ、違いを尋ねていないと具体的に言ったので、両方とも良いです...