Hiding a base method vs Overriding a virtual method

In C#, there are two ways you can pro­vide an alter­na­tive imple­men­ta­tion of an inher­it­ed method:

Over­ride a vir­tu­al method

Unlike Java where every method can be over­rid­den by default unless marked with the final key­word, C# employs a safer, opt-in sys­tem where meth­ods can­not be over­rid­den unless marked with the vir­tu­al key­word.

A vir­tu­al method defined in the base class can be over­rid­den in a derived class by defin­ing a method with the same sig­na­ture and mark­ing it with the over­ride key­word.

Hid­ing a base method

With­out mark­ing a method in the base class with the vir­tu­al key­word it is still pos­si­ble (albeit not rec­om­mend­ed) to pro­vide an over­ride by ‘hid­ing’ the method defined in the base class. All you need to do is to declare the same method sig­na­ture in the derived class.

Philosophical Difference

Under nor­mal cir­cum­stances, hid­ing a base method is a code smell. It unnec­es­sar­i­ly com­pli­cates the rela­tion­ship between the base and derived class as it’s not imme­di­ate­ly clear which method is invoked when you call derived.Foo() if Foo() is declared in both the base and derived class.

To lessen this con­fu­sion, you should use the new key­word when­ev­er you absolute­ly have to hide a method in the base class:

public class BaseClass
{
    public void Foo() { … }
}

public class DerivedClass
{
    public new void Foo() { … }
}

This way, when some­one looks at your code it at least offers some indi­ca­tion that Foo() is an over­ride and more impor­tant­ly, it makes a state­ment of your inten­tion to hide the Foo() method in the base class (as opposed to it look­ing like a mis­take).

Over­rid­ing a vir­tu­al method on the oth­er hand, is very much part and par­cel of object ori­ent­ed design, and an inte­gral part of the Tem­plate pat­tern (one of my favourites :-P) to allow vari­a­tions in the behav­iour of the con­crete class­es. It allows you to make a clear state­ment both in the base and derived class that a method is intend­ed and some­times expect­ed to be over­rid­den.

Semantic Difference

Seman­ti­cal­ly there’s a very sub­tle dif­fer­ence between the two approach­es because the tim­ing in which the method to invoke is deter­mined dif­fers between the two:

  • When you hide a base method the method is resolved at com­pile time – which method is invoked at run­time is pre­de­ter­mined based on what they look like at com­pile time and baked into the com­piled dll.
  • When you over­ride a vir­tu­al method the method is resolved at run­time – the CLR deter­mines which method to invoke by look­ing up a ‘call table’ and find the near­est over­ride of the method.

Here’s a sce­nario where you will notice the dif­fer­ence:

Imag­ine you have two class­es TypeA and TypeB, locat­ed in Assem­blyA and Assem­blyB respec­tive­ly:

public class TypeA // in AssemblyA.dll
{
    public void Foo()
    {
        Console.Write("TypeA.Foo()");
    }

    public virtual void Boo()
    {
        Console.Write("TypeA.Boo()");
    }
}

public class TypeB : TypeA // in AssemblyB.dll
{
}

In my appli­ca­tion which uses both libraries, I have these lines of code:

var typeb = new TypeB();
typeb.Foo();
Console.WriteLine();
typeb.Boo();

And no prizes for guess­ing the out­put of this code:

image

Now, sup­pose I decid­ed at a lat­er date that I wish to over­ride Foo() and Boo() in TypeB:

public class TypeB : TypeA // in AssemblyB.dll
{
    public void Foo()
    {
        Console.Write("TypeB.Foo()");
        base.Foo();
    }

    public override void Boo()
    {
        Console.Write("TypeB.Boo()");
        base.Boo();
    }
}

See­ing as noth­ing else have changed, so I recom­pile only Assem­blyB and dis­trib­ute the new dll, what do you think the out­put is when I rerun my appli­ca­tion? Well, a lit­tle sur­pris­ing­ly:

image

References:

Eric Lippert’s blog post: putting a base in the mid­dle