I am trying to implement IEnumerable<Turtle>
in a class deriving from a base class that already implements IEnumerable<Animal>
.
Why will calling base.Cast<Turtle>()
(or any LINQ method on the base element) in any method from the class Turtle
fail to compile?
It is not possible to replace base
with this
as it obviously results in a StackOverflowException
.
Here is a minimal code sample to replicate the issue:
public interface IAnimal {}
public class Animal : IAnimal {}
public class Turtle : Animal {}
public class AnimalEnumerable : IEnumerable<Animal> {
List<Animal> Animals = new List<Animal>();
IEnumerator<Animal> IEnumerable<Animal>.GetEnumerator() {
return Animals.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() {
return Animals.GetEnumerator();
}
}
public class TurtleEnumerable : AnimalEnumerable, IEnumerable<Turtle> {
IEnumerator<Turtle> IEnumerable<Turtle>.GetEnumerator() {
return base.Cast<Turtle>().GetEnumerator(); //FAILS WITH "CANNOT RESOLVE SYMBOL Cast"
}
}
For some reason, replacing base.Cast<Turtle>().GetEnumerator();
with this.OfType<Animal>().Cast<Turtle>().GetEnumerator();
works without throwing a StackOverflowException
, but I have no idea why.
There are numerous problems with the code given that other answers get into. I want to answer your specific question:
Why will calling
base.Cast<Turtle>()
(or any LINQ method on the base element) in any method from the classTurtle
fail to compile?
Let's go to the specification, section 7.6.8.
A base-access is used to access base class members that are hidden by similarly named members in the current class or struct.
Are you accessing a base class member? NO. An extension method is a member of the static class that contains the extension method, not the base class.
A base-access is permitted only in the block of an instance constructor, an instance method, or an instance accessor.
You're fine here.
When base.I occurs in a class or struct, I must denote a member of the base class of that class or struct.
Again, Cast<T>
is not a member of the base class.
When a base-access references a virtual function member (a method, property, or indexer), the determination of which function member to invoke at run-time (§7.5.4) is changed.
You are not accessing a virtual anything. Extension methods are static.
The function member that is invoked is determined by finding the most derived implementation of the function member with respect to B (instead of with respect to the run-time type of this, as would be usual in a non-base access). Thus, within an override of a virtual function member, a base-access can be used to invoke the inherited implementation of the function member.
So now we see what the purpose of a base access is: to enable a non-virtual dispatch to a virtual member that was overriden in the current type, or to call a base class member that was hidden by a new
member in the current type. That is not what you are trying to use base
for, and therefore you are doomed to failure. Stop using base
off-label like this. Only use it when attempting to do a non-virtual dispatch to a virtual member, or get access to a hidden member.
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