Is it possible to override a non-virtual method?

zfedoran picture zfedoran · Dec 6, 2009 · Viewed 74k times · Source

Is there any way to override a non-virtual method? or something that gives similar results (other than creating a new method to call the desired method)?

I would like to override a method from Microsoft.Xna.Framework.Graphics.GraphicsDevice with unit testing in mind.

Answer

Andrew Hare picture Andrew Hare · Dec 6, 2009

No, you cannot override a non-virtual method. The closest thing you can do is hide the method by creating a new method with the same name but this is not advisable as it breaks good design principles.

But even hiding a method won't give you execution time polymorphic dispatch of method calls like a true virtual method call would. Consider this example:

using System;

class Example
{
    static void Main()
    {
        Foo f = new Foo();
        f.M();

        Foo b = new Bar();
        b.M();
    }
}

class Foo
{
    public void M()
    {
        Console.WriteLine("Foo.M");
    }
}

class Bar : Foo
{
    public new void M()
    {
        Console.WriteLine("Bar.M");
    }
}

In this example both calls to the M method print Foo.M. As you can see this approach does allow you to have a new implementation for a method as long as the reference to that object is of the correct derived type but hiding a base method does break polymorphism.

I would recommend that you do not hide base methods in this manner.

I tend to side with those who favor C#'s default behavior that methods are non-virtual by default (as opposed to Java). I would go even further and say that classes should also be sealed by default. Inheritance is hard to design for properly and the fact that there is a method that is not marked to be virtual indicates that the author of that method never intended for the method to be overridden.

Edit: "execution time polymorphic dispatch":

What I mean by this is the default behavior that happens at execution time when you call virtual methods. Let's say for example that in my previous code example, rather than defining a non-virtual method, I did in fact define a virtual method and a true overridden method as well.

If I were to call b.Foo in that case, the CLR would correctly determine the type of object that the b reference points to as Bar and would dispatch the call to M appropriately.