Initial statement
I'll start with the base code, I have adapted it to run in LINQPad (I did also change it to Write
instead of WriteLine
because I'll not preserve the new lines in the explanation anyway).
class A
{
public A()
{
this.Display();
}
public virtual void Display()
{
Console.Write("A"); //changed to Write
}
}
class B :A
{
public override void Display()
{
Console.Write("B"); //changed to Write
}
}
static void Main()
{
A a = new B();
a.Display();
}
The output is:
BB
In your initial question you said you were expecting:
AB
Whats happening here (as Szymon attempted to explain) is that you are creating an object of type B
and the class B
overrides the method Display
of the class A
. So whenever you call Display
on that object it will be the method of the derived class (B
), even from the constructor of A
.
I will go over all the cases you mention. I want to encourage to read it carefully. Also, be open minded because this does not match what happens in certain other languages.
1) On override of Display method in the derived class
This is the case where you are overriding the method, ie:
public override void Display()
{
Console.Write("B"); //changed to Write
}
When you override, for all practical uses the method that will be used is the method of the derived class. Think of override as replace.
Case 1:
A a = new A(); // ---> AA
We are ok, with that.
Case 2:
B a = new B(); // ---> BB // I expect AB.
As mentioned above, calling Display
on the object will always be the method on the derived class. So, both calls to Display
yield B
.
Case 3:
A a = new B(); // ---> BB // I expect AB.
This is a variant of the same confusion. The object is clearly of type B
, even if you have it in a variable of type A
. Remember that in C# the type is a property of the of the object not of the variable. So, the result is the same as above.
Note: You can still use base.Display()
to access the method that was replaced.
2) Using the NEW keyword in the Display method in derived class
This is the case where you are hiding the method, ie:
public new void Display()
{
Console.Write("B"); //changed to Write
}
When you hide the method, it means that the original method is still available. You can think of it as a different method (that happens to have the same name and signature). That is: the derived class is not replacing overriding that method.
Because of that, when you do a (virtual) call to the object where at compile time it was decided it was going to use the method of the base class... the method of the derived class is not taken into consideration (in practice, it acts as it weren't a virtual call).
Think of it like this: if you call the method using a varible of the base class... the code is not aware that there exists a derived class that hides the method and that that particular call may be executed with one of those object. Instead, it will use the method of the base class, regardless.
Case 1:
B a = new B(); // ---> AB // I Expect AA here.
You see, at compile time the call in the constructor was set to use the method of the base class. That one gives A
. But since the variable is of type B
the compiler is aware that the method was hidden for the second call.
Case 2:
A a = new B(); // ---> AA
Here, neither in the constructor nor in the second call it will use the new method. It is not aware of it.
Case 3:
A a = new A(); // ---> AA
And I think this one is clear.
3) Using base.Display()
This the variant of the code where you do this:
public new void Display()
{
base.Display();
Console.Write("B"); //changed to Write
}
base.Display()
is gonna be the method in the base class (A
), no matter what.
Further reading
You said you want to learn how this works internally.
You can go deeper by reading Microsoft's C# Spec on Virtual Methods
Then read Eric Lippert's Implementing the virtual method pattern in C# (part 1, part 2 and part 3)
You may also be interested:
Others explanations of Virtual Methods from the web: