I have three classes called Animal, Cat and Dog where Cat and Dog inherit from Animal:
public class Animal
{
public void Talk()
{
Console.WriteLine("Parent");
}
}
public class Cat : Animal
{
public new void Talk()
{
Console.WriteLine("Child(Cat)");
}
}
public class Dog : Animal
{
public new void Talk()
{
Console.WriteLine("Child(Dog)");
}
}
I have another method in another class that calls the Talk() method on an animal:
public static Animal FirstKindOfTalk(Animal animal)
{
if (animal.GetType() == typeof(Cat))
{
var changed = animal as Cat;
if (changed is not null)
changed.Talk();
return changed;
}
else if (animal.GetType() == typeof(Dog))
{
var changed = animal as Dog;
if (changed is not null)
changed.Talk();
return changed;
}
return animal;
}
FirstKindOfTalk(new Animal()); => Parent gets printed in the console.
FirstKindOfTalk(new Cat()); => Child(Cat) gets printed in the console.
FirstKindOfTalk(new Dog()); => Child(Dog) gets printed in the console.
I have to explicitly cast the parameter to their own type (Cat or Dog) due to Upcasting, in order to be able to run the specific implementation of those classes from the method Talk(). This is because I'm not using virtual and override in my code, if I used them, then the runtime would run the implementation of the passed in parameter from the method.
The Problem I prefer to write the method as the following:
public static Animal SecondKindOfTalk(Animal animal)
{
var changed = animal;
if (animal.GetType() == typeof(Cat))
{
changed = animal as Cat;
changed.Talk();
return changed;
}
else if (animal.GetType() == typeof(Dog))
{
changed = animal as Dog;
changed.Talk();
return changed;
}
return changed;
}
FirstKindOfTalk(new Animal()); => Parent gets printed in the console.
FirstKindOfTalk(new Cat()); => Parent gets printed in the console.
FirstKindOfTalk(new Dog()); => Parent gets printed in the console.
Can someone explain to me, what is causing this behavior?
I know using virtual and override is the better way, but I have to work on an existing project where methods from the base class aren't defined as virtual, and I cannot change them either.
Yes - the compile-time type of
changedinSecondKindOfTalkis stillAnimal, so you're still callingAnimal.Talk()regardless of the execution-time type.It would be simpler to use pattern matching in a switch statement:
Or potentially even a switch expression and a delegate (which is slightly less performant, admittedly):