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.