There are several issues with your approach. TurtleEnumerable
implements both IEnumerable<Animal>
and IEnumerable<Turtle>
. To be able to use a TurtleEnumerable
instance in a foreach
loop you will have to cast it for the code to compile:
foreach (var turtle in (IEnumerable<Turtle>) turtleEnumerable)
You are also using explicit interface implementations to hide the generic GetEnumerator()
methods. You have to do that because you cannot do overload resolution on return type alone and the two generic GetEnumerator()
methods only differ by return type.
However, this means that a TurtleEnumerable
method cannot call the base GetEnumerator()
method. The reason for this is that base
does not behave like a variable of type "base". Instead it is a reserved word that only can be used to call base class methods. A corollary to this is that extension methods cannot be used with base
. Also, you cannot cast base
so explicit interface implementations on the base class are not callable through base
.
However, you can cast this
but because the generic GetEnumerator()
on TurtleEnumerable
hides the generic GetEnumerator()
on AnimalEnumerable
you will not be able to call into the base class so you will get a stack overflow because at some point the implementation of TurtleEnumerable.GetEnumerator()
will call the same GetEnumerator
.
To make your code compile you need to create a protected IEnumerator<Animal> GetEnumerator()
method in your base class and create your own TurtleEnumerator
class that wraps the base enumerator instance you can get by calling the protected method.
public class TurtleEnumerable : AnimalEnumerable, IEnumerable<Turtle> {
IEnumerator<Turtle> IEnumerable<Turtle>.GetEnumerator() {
return new TurtleEnumerator(base.GetEnumerator());
}
sealed class TurtleEnumerator : IEnumerator<Turtle> {
IEnumerator<Animal> animalEnumerator;
public TurtleEnumerator(IEnumerator<Animal> animalEnumerator) {
this.animalEnumerator = animalEnumerator;
}
public Turtle Current {
get { return (Turtle) animalEnumerator.Current; }
}
Object IEnumerator.Current {
get { return Current; }
}
public Boolean MoveNext() {
return animalEnumerator.MoveNext();
}
public void Reset() {
animalEnumerator.Reset();
}
public void Dispose() {
animalEnumerator.Dispose();
}
}
}
All in all having a collection the implements both IEnumerable<Base>
and IEnumerable<Derived>
will get you into a lot of trouble. What are you trying to achieve by using this design?
Using a generic List<T>
and contravariance you can do things like this:
IEnumerable<Turtle> turtles = new List<Turtle>();
IEnumerable<Animal> animals = (IEnumerable<Animal>) turtles;
You can also replace List<T>
by your own generic collection type if that is required.