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

很清楚,它应该打印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();
}

这很棘手,因为它使用显式接口实现。

我还没有测试过,但我认为这应该对你有用。显然,这样是个坏主意……

编辑:或者,只需将变量类型更改为IEnumeratorIEnumerator<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 回答