I ran into a interesting issue last week and I am not sure I truly understand the polymorphic nature of the following code. I created this sample based some code that I wrote.
Basic Setup
- I have a class "Trainer" that knows how to train a animal.
- I use that as a base class and created a subclass "DogTrainer" that knows how to only train dogs.
- I created a function pointer using the superclass as the return type.
- I then call that function getting a new instance of the subclass "DogTrainer".
- I then call the "Train" method of the instance returned from the function pointer.
- The "Train" method invokes the "Trainer" - "Train" method not the "DogTrainer" - "Train" method as expected
Here is the code
// Does not work as expected
// Calls the Trainer Train not the DogTrainer Train
var getTrainer = new Func<Trainer>(() => new DogTrainer(new Dog()));
var funcTrainer = getTrainer();
Console.WriteLine(funcTrainer.Train());
Now if I use a Interface as the return type it does work as expected "IF" I have the interface directly marked on the "DogTrainer" subclass
// Works as expected
var getITrainer = new Func<ITrainer>(() => new DogTrainer(new Dog()));
var funcITrainer = getITrainer();
Console.WriteLine(funcITrainer.Train());
If I do not have the interface on the subclass it does not work as expected. See Example
// Does not work as expected
// Calls the Trainer Train not the Dog Trainer Train
var getITrainerWithNoInterface = new Func<ITrainer>(() => new DogTrainerWithNoInterface(new Dog()));
var funcITrainerWithNoInterface = getITrainerWithNoInterface();
Console.WriteLine(funcITrainerWithNoInterface.Train());
If someone could let me know what I am missing here, this behavior is not what I expected. When I discovered this bug in my code I was able to solve it, what I am looking for here is the "Why" this is happening.
Here is DogTrainerWithNoInterface
which is likely the main part of the puzzle (Trainer:ITrainer
)
public class DogTrainerWithNoInterface : Trainer
{
public DogTrainerWithNoInterface(IAnimal animal)
: base(animal)
{ }
public new string Train()
{
return $"Speak Ubu, Speak : {Animal.Speak()}";
}
}