web-dev-qa-db-ja.com

IEnumerator.Reset()を使用するにはどうすればよいですか?

呼び出す正しい方法はどれくらい正確ですか IEnumerator.Reset

ドキュメントには次のように書かれています。

Resetメソッドは、COMの相互運用性のために提供されています。必ずしも実装する必要はありません。代わりに、実装者は単にNotSupportedExceptionをスローできます。

さて、それは私がそれを呼ぶことになっていないという意味ですか?

フロー制御に例外を使用したくなるのはsoです:

using (enumerator = GetSomeExpensiveEnumerator())
{
    while (enumerator.MoveNext()) { ... }

    try { enumerator.Reset(); } //Try an inexpensive method
    catch (NotSupportedException)
    { enumerator = GetSomeExpensiveEnumerator(); } //Fine, get another one

    while (enumerator.MoveNext()) { ... }
}

それは私たちがそれを使用することになっている方法ですか?それとも、マネージコードから使用するつもりはありませんか?

35
user541686

決して;最終的にこれは間違いでした。シーケンスを複数回繰り返す正しい方法は、.GetEnumerator()を再度呼び出すことです。つまり、foreachを再度使用します。データが再現できない(または繰り返すのに費用がかかる)場合は、.ToList()などを使用してデータをバッファリングします。

イテレータブロックがこのメソッドの例外をスローすることは、言語仕様の正式な要件です。そのため、それが機能していることを信頼することはできません。これまで。

52
Marc Gravell

使用しないことをお勧めします。最新のIEnumerable実装の多くは、例外をスローするだけです。

列挙子を取得することは、「高価」になることはほとんどありません。高価になる可能性のあるものすべてを(完全に)列挙しています。

8
Stephen Cleary
public class PeopleEnum : IEnumerator
{
    public Person[] _people;

    // Enumerators are positioned before the first element 
    // until the first MoveNext() call. 
    int position = -1;

    public PeopleEnum(Person[] list)
    {
        _people = list;
    }

    public bool MoveNext()
    {
        position++;
        return (position < _people.Length);
    }

    public void Reset()
    {
        position = -1;
    }

    object IEnumerator.Current
    {
        get
        {
            return Current;
        }
    }

    public Person Current
    {
        get
        {
            try
            {
                return _people[position];
            }
            catch (IndexOutOfRangeException)
            {
                throw new InvalidOperationException();
            }
        }
    }
}
1
Petar