I am trying to understand how inheritance works in C#. I wrote the following code:
class Program
{
static void Main(string[] args)
{
Animal animal = new Dog();
animal.OverRideMe();
//animal.NewMethod();
Dog dog = (Dog)animal;
dog.OverRideMe();
dog.NewMethod();
Console.Read();
}
}
public abstract class Animal
{
public Animal()
{
Console.WriteLine("Base Constructor");
}
public virtual void OverRideMe()
{
Console.WriteLine("In Base Class's OverRideMe");
Console.Read();
}
}
public class Dog : Animal
{
public Dog()
{
Console.WriteLine("Derived Constructor");
}
public override void OverRideMe()
{
Console.WriteLine("In Derived Class's OverRideMe");
Console.Read();
}
public void NewMethod()
{
Console.WriteLine("In Derived Class's NewMethod");
Console.Read();
}
}
The CIL(Common Intermediate Language) code for the Main() looks like the following:
.method private hidebysig static
void Main (
string[] args
) cil managed
{
// Method begins at RVA 0x2050
// Code size 42 (0x2a)
.maxstack 1
.entrypoint
.locals init (
[0] class ConsoleApplication1.Animal animal,
[1] class ConsoleApplication1.Dog dog
)
IL_0000: nop
IL_0001: newobj instance void ConsoleApplication1.Dog::.ctor()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: callvirt instance void ConsoleApplication1.Animal::OverRideMe()
IL_000d: nop
IL_000e: ldloc.0
IL_000f: castclass ConsoleApplication1.Dog
IL_0014: stloc.1
IL_0015: ldloc.1
IL_0016: callvirt instance void ConsoleApplication1.Animal::OverRideMe()
IL_001b: nop
IL_001c: ldloc.1
IL_001d: callvirt instance void ConsoleApplication1.Dog::NewMethod()
IL_0022: nop
IL_0023: call int32 [mscorlib]System.Console::Read()
IL_0028: pop
IL_0029: ret
} // end of method Program::Main
The lines in CIL that are troubling me are:
IL_000f: castclass ConsoleApplication1.Dog
IL_0014: stloc.1
IL_0015: ldloc.1
IL_0016: callvirt instance void ConsoleApplication1.Animal::OverRideMe()
IL_001b: nop
IL_001c: ldloc.1
IL_001d: callvirt instance void ConsoleApplication1.Dog::NewMethod()
After the castclass of animal to Dog type the code executes dog.OverRideMe();. This is translated to CIL as
IL_0016: callvirt instance void ConsoleApplication1.Animal::OverRideMe()
I had cast the animal object to Dog type. Why should dog.OverRideMe(); be translated to the above statement in CIL? The output of the above code is:
This output has nothing to do with Base class Animal but CIL still places a call to it.
You're invoking a virtual method. Virtual method invocation is determined by the runtime type of an object. You can call it a Dog
all you want, but the compiler is still going to emit instructions to determine the appropriate method to invoke at runtime. Starting with the compile-time type of dog
, it walks up the inheritance chain until it finds the "top-level" definition1 of OverRideMe
and it emits a virtual method invocation for that. In this case, the highest place in the inheritance chain that OverRideMe
is defined is in Animal
; thus, it emits a virtual method invocation for Animal.OverRideMe
.
Here's a previous answer that might help you understand what is going on a little better.
1: The highest place in the inheritance chain where the method is defined. Some care has to be taken here to understand how method hiding and what not impact this.
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