Could someone explain in a more didactic way what these interfaces are for
IEnumerable
is an interface that marks the classes that wish to implement it so that it is known that it can be iterated through an iterator. Obviously this should only be used on objects that are data sequences, otherwise it makes no sense to iterate there. The method is used to obtain the iterator. Most of the times the implementation of this method is the same or very similar.
Whenever implementing the IEnumerable
will have to implement, somehow, in the class or elsewhere the interface IEnumerator
.
The iterator is defined by the interface IEnumerator
which proposes to have the necessary mechanism to iterate, ie need a state with the current object (Current
), what is the next item on the list (MoveNext()
) and how to restart iterator scanning (Reset()
).
what advantages they bring to iterations that a "simple loop" does not bring?
If the language does not determine how to loop a data sequence, the only way you can create a type that is an iterable data sequence is by providing a mechanism that says:
- how to take the dice
- the next and
- how to start over.
Your type should provide the code that does this properly and if possible with the best possible performance for your case. In this case the language does in array and string, so in theory these types would not need to have these interfaces, but they have for use in other situations that the language does not control.
Considering that Ienumerable only has one method that calls the Ienumerator and that to iterate a collection we do not have the obligation to implement the Ienumerable, it follows a question: What is the relationship of Ienumerable with the Ienumerator?
That’s not quite true. It’s even possible in most cases not to implement the IEnumerable
in a collection, but a lot of things will not be possible to be made. Nor can we consider it a collection, at least not an eternal one. It will be a beautiful one of a gambiarra. It has collection that simply is not possible to iterate without doing something totally out of the pattern. And the purpose of these interfaces is to maintain a standard way of doing things.
Can anyone explain to me why this code works even though the codes are not most commonly taught to implement Ienumerator?
The code works because that’s what it has to do.
- he picks up the iterator and throws it at an object
- the
MoveNext()
takes the next element of the sequence, in case you should take the first
- accesses the element inside the loop
- check if you have the next item to decide whether to continue or not, since the
MoveNext()
returns a boolean.
Exactly how this works internally is specific iterator problem, is implementation detail.
Actually this code is not good because it leaks memory leaving the iterator alive even after finishing its use. In other situations it is possible that a cast is necessary to use the element since it returns a object
, unless you use a IEnumerator<T>
which allows you to return the real type of the object. All this the compiler puts to you, so it is better to use the foreach
than doing at hand, the compiler knows what he’s doing, the programmer doesn’t always.
The foreach
can only work on objects that have the interface IEnumerable
since it needs to iterate in the data sequence.
In the link provided in the question actually has how the code gets after compiled (it is made a Lowering).
If the . NET were written today it would be different, perhaps the idea by Jared Parsons is the implementation, which is much better than the adopted.