views:

178

answers:

4

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.

+8  A: 

No, you cannot overload 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.

Andrew Hare
Although "execution time polymorphic dispatch" is technically the correct way to say it, I imagine this probably goes over the heads of almost everybody!
Orion Edwards
While it is true that the author may have intended to disallow method overriding it is not true that it was necessarily the correct thing to do. I feel that the XNA team should have implemented a IGraphicsDevice interface to allow the user more flexibility in debugging and unit testing. I am forced to do some very ugly things and this should have been foreseen by the team. Further discussion can be found here: http://forums.xna.com/forums/p/30645/226222.aspx
Arriu
@Orion - fair enough, I have added an explanation :)
Andrew Hare
@Orion I did not understand it either but after a quick google I appreciated seeing the use of the "correct" terms.
Arriu
+3  A: 

No you can't.

You can only override a virtual method - see the MSDN here:

In C#, derived classes can contain methods with the same name as base class methods.

  • The base class method must be defined virtual.
ChrisF
+3  A: 

If the base class isn't sealed then you can inherit from it and write a new method that hides the base one (use the "new" keyword in the method declaration). Otherwise no, you cannot override it because it was never the original authors intent for it to be overridden, hence why it isn't virtual.

slugster
+1  A: 

I think you're getting overloading and overriding confused, overloading means you have two or more methods with the same name but different sets of parameters while overriding means you have a different implementation for a method in a derived class (thereby replacing or modifying the behaviour in it's base class).

If a method is virtual, you can override it using the override keyword in the derrived class. However, non-virtual methods can only hide the base implementation by using the new keyword in place of the override keyword. The non-virtual route is useless if the caller accesses the method via a variable typed as the base type as the compiler would use a static dispatch to the base method (meaning the code in your derrived class would never be called).

There is never anything preventing you from adding an overload to an existing class, but only code that knows about your class would be able to access it.

Rory