问题描述
尽管事实是,永远不要使用 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);
}
很明显,它应该两次打印True
和3
.而不是结果是
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?
推荐答案
是:您要将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...
或者,只需将变量类型更改为IEnumerator
或IEnumerator<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< T> .Enumerator IEnumerator.Reset()方法的实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!