6

事実にもかかわらず、そのIEnumerator.Resetメソッドは決して使用されるべきではありません.内のメソッド実装の奇妙な動作を見つけましたList<T>.

.NET Framework ソース コードをどのように調べても (参照ソースと ILSpy で試してみました)、メソッドは次のように実装されます。

void System.Collections.IEnumerator.Reset() {
    if (version != list._version) {
        ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
    }

    index = 0;
    current = default(T);
}

ただし、メソッドがまったく呼び出されていないようです。次のコードを検討してください。

var list = new List<int>(1) { 3 };
using (var e = list.GetEnumerator())
{
    Console.WriteLine(e.MoveNext());
    Console.WriteLine(e.Current);

    ((IEnumerator)e).Reset();

    Console.WriteLine(e.MoveNext());
    Console.WriteLine(e.Current);
}

2回印刷Trueする必要があることは明らかです。3その代わりに結果は

True
3
False
0

私が見逃している簡単な説明はありますか?

4

1 に答える 1

15

私が見逃している簡単な説明はありますか?

はい: ここでボクシングをしていList.Enumeratorます:

((IEnumerator)e).Reset();

それは既存のもののコピーを取り、それをリセットします - オリジナルを一体のままにします。

実際の列挙子をリセットするには、次のようなものが必要です。

var list = new List<int>(1) { 3 };
var e = list.GetEnumerator();
// Can't use "ref" with a using statement
try
{
    Console.WriteLine(e.MoveNext());
    Console.WriteLine(e.Current);

    Reset(ref e);

    Console.WriteLine(e.MoveNext());
    Console.WriteLine(e.Current);
}
finally
{
    e.Dispose();
}

static void Reset<T>(ref T enumerator) where T : IEnumerator
{
    enumerator.Reset();
}

明示的なインターフェイスの実装を使用するため、注意が必要です。

私はそれをテストしていませんが、それはあなたにとってうまくいくはずです。明らかに、これを行うのは悪い考えです...

編集: または、変数の型をIEnumeratororIEnumerator<int>に変更するだけです。次に、一度ボックス化され、Resetメソッドはボックス化された値を変更します。

var list = new List<int>(1) { 3 };
using (IEnumerator e = list.GetEnumerator())
{
    Console.WriteLine(e.MoveNext());
    Console.WriteLine(e.Current);

    e.Reset();

    Console.WriteLine(e.MoveNext());
    Console.WriteLine(e.Current);
}
于 2013-09-30T17:52:54.423 に答える