When is IEnumerable.GetEnumerator called instead of IEnumerable <T> .GetEnumerator?
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(); } } Launch:
myWords m = new myWords(); foreach (var s in m) { Console.WriteLine(s); } Productivity
I 2 ve you2 // notice "2", so the generic Ienumerator has executed. I understand that the version of non-generic IEnumerator is for compatibility.
Question:
- In which scenario will the non-generic be called?
- How can I get my code to run with non-shared
IEnumerator?
Other answers seem to miss the point.
Interfaces do not matter at all if the type (compilation time) of what is beeing foreach ed has a public non-basic non-static method called GetEnumerator , which takes null arguments. (The return type of this method can be any, general or non-general: interfaces do not matter.)
So the reason the first of your methods is called is because it is a public method.
You can change this:
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 the following:
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 advisable to implement IEnumerable<> . Then your type can be used with Linq (extension methods on IEnumerable<> ) and can be used as an argument for other methods that just require IEnumerable<> .
In addition, it is reasonable to have a method (or an explicit interface implementation) that returns a non-generic IEnumerator method call (or an explicit interface implementation) that returns an IEnumerator<> . Having two returnable individual sequences is really confusing (but it's nice to ask and answer questions about how everything works).
The IEnumerator non-generator will be executed whenever the code passes the class to a non-common interface:
((IEnumerable)myWords).GetEnumerator(); // this calls the non-generic one This is mostly true if you pass your class to some inherited function that requires a non-generic IEnumerator.
So, if you have a library containing a function, and you pass your class to this function, it will use a 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 fair to simply implement a non-core IEnumerator using the generic:
public class myWords : IEnumerable<string> { .... IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); } } Thus, you can be sure that both of them have the same effects.
The non-original version of IEnumerable implemented with an explicit interface implementation. This means that you can only call an explicitly implemented function by casting to the interface.
The reason IEnumerable explicitly implemented is that the method signatures are the same except for the return type.
Listing myWords explicitly on IEnumerable allows you to invoke a non-generic version as follows: (IEnumerable)myWords .
The C # manual explains how this works: Explicit interface implementation .