问题
when I go to the definition of List<> I can see it has a public struct Enumerator that implements the interfaces IEnumerator<T>
, IDisposable and IEnumerator.
IEnumerator should force the implementation of Reset - besides Current and MoveNext. Yet only Current and MoveNext are implemented.
How can that be?
Where do I find the Reset() of List<>?
var list = new List<int>();
list.Add(23);
list.Add(44);
var Enumerator = list.GetEnumerator();
while (Enumerator.MoveNext())
{
Console.WriteLine(Enumerator.Current);
}
Enumerator.
And when I try it in code there is no Reset():
Ok - I tried to show a screenshot, but they don't let me.
But copying above code shows no Reset-Method after the Dot-operator (.) of Enumerator.
Would someone know and throw some light on this?
I see it calls the Reset of IEnumerator which is part of mscorlib.
var list = new List<int>();
list.Add(23);
list.Add(44);
var Enumerator = list.GetEnumerator();
Enumerator.MoveNext();
Enumerator.MoveNext();
Console.WriteLine(Enumerator.Current);
((IEnumerator<int>)Enumerator).Reset();
Enumerator.MoveNext();
And yet as IEnumerator is an interface how can code be called by it?
Reset() in IEnumerator should just be a definition and the implementation left to whoever uses the interface.
But somehow here actual functionality is provided by just defining the interface to be implemented. Nowhere do I see the actual implementation - and that part I do not understand.
回答1:
It's explicitly implemented, as shown in the documentation, as is IEnumerator.Current
. In other words, you can only call the method on a value with a compile-time type of IEnumerator
.
So you could use:
// Casing changed to be more conventional
var enumerator = list.GetEnumerator();
((IEnumerator)enumerator).Reset();
However, that would then box the value anyway (as List<T>.Enumerator
is a struct) which would make it pointless. It's not clear whether you're just interested in the apparent lack of a Reset
method, but in general I would strongly advise you not to rely on IEnumerator.Reset
- it's very often not implemented, and IMO it shouldn't have been part of the interface to start with...
回答2:
You think you are using the IEnumerator<> interface, but you are not. Type inference is getting the better of you, the type of your Enumerator variable is actually List.Enumerator<>, a structure type. Use the interface and you'll have no trouble:
IEnumerator<int> Enumerator = list.GetEnumerator();
while (Enumerator.MoveNext()) {
Console.WriteLine(Enumerator.Current);
}
Enumerator.Reset(); // Fine
It doesn't work on List.Enumerator<> because Microsoft intentionally hid the Reset() method implementation by making it private. Note how iterators for other collection classes like Dictionary and HashSet behave this way as well.
That could use an explanation. IEnumerator encapsulates a forward-only iterator and is the foundation upon which the house of Linq was built. The Reset() method is a problem, that's no longer strictly forward-only. You move the iterator back. In practice, you'll find out that in many cases trying to call Reset() produces a NotImplementedException. Not a problem for List, easy to go back. Big problem for Linq.
IEnumerator should have been designed without a Reset() method. But it wasn't the .NET designers' choice, this was nailed down before 1996, long before anybody started working on .NET. Iterators were an existing concept in COM Automation. Which was the extension model for Visual Basic version 4, it replaced the 16-bit VBX model.
Wildly popular, almost any language runtime on Windows implements it. And still very heavily used in .NET programs. Skillfully hidden in most cases, no way to tell that you are using it when you put a WebBrowser on your UI for example. The .NET designers were forced to implement it as well to have a shot at getting programmers to move to .NET. Also the source of the very troublesome ICloneable interface.
来源:https://stackoverflow.com/questions/31915223/where-does-a-generic-list-implement-reset