Question regarding IEnumerable and IEnumerator
What is the difference between IEnumerator and IEnumerable?
Jason's answer is good but I thought I'd just add how I think about this. Imagine you have a sequence:
1, 1, 2, 3, 5, 8, 13, ...
Now imagine you have an arrow pointing at some position of that sequence:
1, 1, 2, 3, 5, 8, 13, ...
^
An "arrow" is an object that can do two things. First, it can give you the thing it is pointing at. Second, it can make itself point at the next thing.
IEnumerator is an arrow. It has a property, Current, that gives you the thing it is pointing at. It has a method, MoveNext() that makes itself point at the next thing.
How do you get an arrow in the first place? You need an arrow factory. You ask the factory for an arrow, and it gives you an arrow that points to the first element in the sequence.
IEnumerable is an arrow factory. It has a method, GetEnumerator, that gives you an arrow to the first element of the sequence.
A nice property of this scheme is that you can have multiple arrows pointing to different places in the same sequence.
what are the benefits of implementing generic interface IEnumerable instead of just IEnumerable?
Suppose the sequence is of integers. If you implement IEnumerable
then when you say
foreach(int x in mysequence)
what that will actually do is convert the int in the sequence to object, boxing the integer, and then immediately unbox the object back to integer, adding a completely unnecessary memory allocation to every single operation. If the compiler knows that the sequence is of integers then it can skip the unnecessary boxing operation.
Suppose the sequence is of strings. If you implement IEnumerable<string>
then you can say:
string first = mysequence.First();
If you don't, then you have to say
string first = (string)mysequence.First();
which is unnecessary and error-prone. Rather than instruct the compiler via a cast that the type is string, you can simply guarantee that the type is string by using the type system.
1) What is
IEnumerator
for? Whats the difference betweenIEnumerator
andIEnumerable
?
IEnumerator
is an interface that represents methods that let you enumerate a sequence. The difference between IEnumerator
and IEnumerable
is that the former represents the contract for objects that let you enumerate a sequence, and the latter represents the contract for objects that are a sequence that can be enumerated over.
public IEnumerator<string> GetEnumerator() {
yield return "first";
yield return "second";
}
IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerator();
}
2) What is it for? It just calls above method.
The former represents an implementation of the method GetEnumerator
on the contract IEnumerable<string>
. The latter represents an explicit implementation of the method GetEnumerator
on the contract IEnumerable
. The issue is that both contracts have a method named GetEnumerator
but with different return types so that a method can't simultaneously satisfy both contracts (any class implementing IEnumerable<T>
must also implement IEnumerable
as IEnumerable<T> : IEnumerable
). The latter invokes the implementation of IEnumerable<string>.GetEnumerator
as that is a sensible implementation that returns an IEnumerator
as IEnumerator<string> : IEnumerator
.
3) Lastly what benefits I have from implementing generic interface
IEnumerable<string>
instead of justIEnumerable
?
Strong typing. You know that the elements in a sequence IEnumerable<string>
are all instances of String
whereas you don't know that for IEnumerable
and could end up trying to cast an element of the latter to an instance of String
when it can not be.
1) What is IEnumerator for?
IEnumerator is the real working part with the MoveNext() and Current members.
Whats the difference between IEnumerator and IEnumerable
IEnumerable is the interface for a collection to signal that it has an GetEnumerator().
2) [non-generic GetEnumerator] What is it for? It just calls above method
The non-generic method is just there for backward compatibility. Note that it is moved 'out of sight' as much as possible by use of the explicit implementation. Implement it because you must and then forget about it.
3) Lastly what benefits I have from implementing genetic interface IEnumerable instead of just IEnumerable
When used with foreach
the adavantage is small, as foreach will type-cast the looping variable. It will let you use var
in the foreach:
foreach (var s in myClassInstance) // needs `IEnumerable<string>`
foreach (string s in myClassInstance) // works with `IEnumerable` as well
But with IEnumerable<string>
you also have a type-safe interface to other areas, most notably LINQ:
MyClass mc = new MyClass ();
string s = mc.FirstOrDefault();