Looking at this code :
public class myWords : IEnumerable<string>
{
string[] f = "I love you".Split(new string[]{"lo"},StringSplitOptions.RemoveEmptyEntries);
public IEnumerator<string> GetEnumerator()
{
return f.Select(s => s + "2").GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return f.Select(s => s + "3").GetEnumerator();
}
}
Running :
myWords m = new myWords();
foreach (var s in m)
{
Console.WriteLine(s);
}
Yields
I 2
ve you2 // notice "2", so the generic Ienumerator has executed.
I understand that the non-generic IEnumerator
version is for compatibility.
Question:
IEnumerator
?IEnumerable<T> is the base interface for collections in the System. Collections. Generic namespace such as List<T>, Dictionary<TKey,TValue>, and Stack<T> and other generic collections such as ObservableCollection<T> and ConcurrentStack<T>.
IEnumerable is an interface that allows us to iterate over a collection; it does so by exposing a single GetEnumerator() method, which in turn returns an IEnumerator: a simple interface that provides methods to access the current element in the collection, move to the next item, and reset back to the beginning of the ...
An IEnumerator is a thing that can enumerate: it has the Current property and the MoveNext and Reset methods (which in . NET code you probably won't call explicitly, though you could). An IEnumerable is a thing that can be enumerated...which simply means that it has a GetEnumerator method that returns an IEnumerator .
The C# GetEnumerator() method is used to convert string object into char enumerator. It returns instance of CharEnumerator. So, you can iterate string through loop.
The non-generic IEnumerator will be executed whenever code casts the class to the non-generic interface:
((IEnumerable)myWords).GetEnumerator(); // this calls the non-generic one
This is mostly relevant if you pass your class to some legacy function that requires a non-generic IEnumerator.
So if you have some library that contains a function and you pass your class to this function, it will use the non-generic IEnumerator
DoSomeStuffWithAnIEnumerable(IEnumerable x)
{
var foo = x.GetEnumerator();
// or, as stackx said, an example with foreach:
foreach (var foo2 in x)
Console.WriteLine(foo2);
}
DoSomeStuffWithAnIEnumerable(new myWords());
Note that it is perfectly valid to simply implement the non-generic IEnumerator using the generic one:
public class myWords : IEnumerable<string>
{
....
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
That way you can be sure that they both have the same effects.
The other answers sort of miss the point.
Interfaces do not matter at all if the (compile-time) type of what is beeing foreach
ed has a public
non-generic non-static method called GetEnumerator
which takes zero arguments. (The return type of this method can be anything, generic or non-generic: interfaces will not matter.)
So the reason why the first of your methods is called, is that this is the public
method.
You can change that:
public class myWords : IEnumerable<string>
{
string[] f = "I love you".Split(new string[]{"lo"},StringSplitOptions.RemoveEmptyEntries);
IEnumerator<string> IEnumerable<string>.GetEnumerator()
{
return f.Select(s => s + "2").GetEnumerator();
}
public IEnumerator GetEnumerator()
{
return f.Select(s => s + "3").GetEnumerator();
}
}
To prove that interfaces are not needed, try this:
public class myWords // no interfaces!
{
string[] f = "I love you".Split(new string[]{"lo"},StringSplitOptions.RemoveEmptyEntries);
public IEnumerator GetEnumerator()
{
return f.Select(s => s + "3").GetEnumerator();
}
}
However, it is wise to implement IEnumerable<>
. Then your type can be used with Linq (extension methods on IEnumerable<>
), and can be used as argument to other methods that simply require an IEnumerable<>
.
Also, it is wise to have the method (or explicit interface implementation) that returns the non-generic IEnumerator
just call through to the method (or explicit interface implementation) that returns IEnumerator<>
. Having the two return distinct sequences is really confusing (but nice for asking and answering questions on how things work).
The non-generic version of the IEnumerable
is implemented with an explicit interface implementation. This means that you can only call the explicitly implemented function by casting to the interface.
The reason IEnumerable
is implemented explicitly is that the method signatures are the same except for the return type.
Casting myWords
explicitly to IEnumerable
allows you to call the non-generic version like this: (IEnumerable)myWords
.
The C# Guide explains how this works: Explicit interface implementation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With