List< T> .Enumerator IEnumerator.Reset()方法的实现 [英] List<T>.Enumerator IEnumerator.Reset() method implementation

查看:78
本文介绍了List< T> .Enumerator IEnumerator.Reset()方法的实现的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

尽管事实是,永远不要使用 IEnumerator.Reset方法,但我发现List<T>.

Despite the fact, that IEnumerator.Reset method should never be used I found strange behavior of the method implementation within List<T>.

无论您如何检查.NET Framework源代码(尝试使用参考源和ILSpy),该方法都将实现如下:

No matter how you examine the .NET Framework Source Code (tried with reference source and ILSpy) the method is implemented as following:

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

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

但是,似乎根本没有调用该方法!考虑代码:

However, it looks like the method is never called at all! Consider the code:

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

很明显,它应该两次打印True3.而不是结果是

It's pretty clear, that it should print True and 3 twice. Instead of that the result is

True
3
False
0

我缺少任何简单的解释吗?

Any simple explanation I'm missing?

推荐答案

我缺少任何简单的解释吗?

Any simple explanation I'm missing?

是:您要将List.Enumerator装箱在这里:

Yes: you're boxing the List.Enumerator here:

((IEnumerator)e).Reset();

获取现有副本的副本并将其重置-将原始副本留在一个副本中.

That takes a copy of the existing one and resets it - leaving the original in one piece.

要重置实际枚举器,您将需要以下内容:

To reset the actual enumerator, you'd need something like this:

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

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

It's tricky because it uses explicit interface implementation.

我还没有测试过,但是我认为这应该对您有用.显然,这是一个坏主意.

I haven't tested it, but I think that should work for you. Obviously it's a bad idea to do this...

或者,只需将变量类型更改为IEnumeratorIEnumerator<int>即可.然后将其装箱一次,然后Reset方法将更改装箱的值:

Alternatively, just change your variable type to IEnumerator or IEnumerator<int> to start with. Then it will be boxed once, and the Reset method will mutate the boxed value:

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

这篇关于List&lt; T&gt; .Enumerator IEnumerator.Reset()方法的实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆