113

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.

zfedoran
  • 2,986
  • 4
  • 22
  • 25
  • 8
    Do you mean *overload* or *override*? Overload = add a method with the same name but different parameters (e.g. different overloads of Console.WriteLine). Override = (roughly) change the default behaviour of the method (e.g. a Shape.Draw method which has different behaviour for Circle, Rectangle, etc.). You can always *overload* a method in a derived class, but *overriding* only applies to virtual methods. – itowlson Dec 05 '09 at 23:52

10 Answers10

129

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.

AgentFire
  • 8,944
  • 8
  • 43
  • 90
Andrew Hare
  • 344,730
  • 71
  • 640
  • 635
  • 7
    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 Dec 06 '09 at 00:08
  • 3
    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 – zfedoran Dec 06 '09 at 00:18
  • 1
    @Orion - fair enough, I have added an explanation :) – Andrew Hare Dec 06 '09 at 00:20
  • 3
    @Orion I did not understand it either but after a quick google I appreciated seeing the use of the "correct" terms. – zfedoran Dec 06 '09 at 00:24
  • 29
    I don't buy the "author didnt intend for it" argument at all. That's like saying the inventor of the wheel didn't anticipate wheels being put on cars so we can't use them on cars. I know how the wheel/method works and I want to do something slightly different with it. I don't care if the creator wanted me to or not. Sorry for trying to revive a dead thread. I just need to blow of some steam before I figure out some really inconvenient way to get around this problem I'm in :) – Jeff Apr 18 '11 at 22:11
  • 1
    @Jeff, you are actually reinforcing the initial argument. The inventor of the wheel didn't anticipate the wheel being reinvented (extended). Using wheels on cars is an example of composition, which C#'s default non-virtual methods encourage. – Robert Christian Mar 09 '12 at 00:17
  • 2
    So what about when you inherit a large codebase, and need to add a test for new functionality, but in order to test that you need to instantiate a whole lot of machinery. In Java, I'd just extend those parts and override the methods required with stubs. In C#, if the methods aren't marked as virtual, I have to find some other mechanism (mocking library or such, and even then). – Adam Parkin Sep 16 '14 at 15:37
  • Here are two links that helped me understand what Andrew was describing by "execution time polymorphic dispatch." http://stackoverflow.com/a/1014378/450668 https://msdn.microsoft.com/en-us/library/ms173153.aspx Basically, if you use the `new` keyword, the method call is set at compile-time based on the explicitly declared types, whereas `override` will allow the method lookup to be based on the actual object type as determined at runtime. You can see this in action here, paying particular attention to what happens with lines 31 and 32: https://dotnetfiddle.net/4RSJPR – Josh Nov 09 '16 at 17:20
  • Can any one tell me which principle is violated here? Is it Liskov Substitution Principle? – Abdul Rafay Apr 18 '20 at 17:20
  • Nothing is violated here. Almost in every language you can override any methods (even private, even static). I think that language design one of the reasons why there so many abandoned libraries and why people tend to reinvent their own wheels instead of use someones just with little modifications. – Andrey May 08 '22 at 21:12
25

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.
Community
  • 1
  • 1
ChrisF
  • 134,786
  • 31
  • 255
  • 325
10

You can't override non-virtual method of any class in C# (without hacking CLR), but you can override any method of interface the class implements. Consider we have non-sealed

class GraphicsDevice: IGraphicsDevice {
    public void DoWork() {
        Console.WriteLine("GraphicsDevice.DoWork()");
    }
}

// with its interface
interface IGraphicsDevice {
    void DoWork();
}

// You can't just override DoWork in a child class,
// but if you replace usage of GraphicsDevice to IGraphicsDevice,
// then you can override this method (and, actually, the whole interface).

class MyDevice: GraphicsDevice, IGraphicsDevice {
    public new void DoWork() {
        Console.WriteLine("MyDevice.DoWork()");
        base.DoWork();
    }
}

And here's demo

class Program {
    static void Main(string[] args) {

        IGraphicsDevice real = new GraphicsDevice();
        var myObj = new MyDevice();

        // demo that interface override works
        GraphicsDevice myCastedToBase = myObj;
        IGraphicsDevice my = myCastedToBase;

        // obvious
        Console.WriteLine("Using real GraphicsDevice:");
        real.DoWork();

        // override
        Console.WriteLine("Using overriden GraphicsDevice:");
        my.DoWork();

    }
}
6

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
  • 49,403
  • 14
  • 95
  • 145
3

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
  • 2,722
  • 1
  • 20
  • 11
2

The answer to this question is not entirely No. It depends on how you structure your inheritance and access the instances of your classes. If your design meets the following, you would be able to override non-virtual method from base class with the new modifier:

  • The method is declared in an interface that your classes inherit from
  • You are accessing the class instances using the interface

Take example of the following:

interface ITest { void Test(); }
class A : ITest { public void Test(){Console.WriteLine("A");} }
class B : A { public new void Test(){Console.WriteLine("B");} }
ITest x = new B(); 
x.Test(); // output "A"

calling x.Test() will output "A" to the console. However if you re-declare the interface in the definition of class B, x.Test() will output B instead.

interface ITest { void Test(); }
class A : ITest { public void Test(){Console.WriteLine("A");} }
class B : A, ITest { public new void Test(){Console.WriteLine("B");} }
ITest x = new B();
x.Test(); // output "B"
TDao
  • 514
  • 4
  • 13
  • Just for your information, your answer is a duplicate of https://stackoverflow.com/a/59833168/1836540 – Vyacheslav Napadovsky Aug 07 '21 at 10:03
  • I just read your post @VyacheslavNapadovsky but I don't think it's the same. The key thing I'm trying to highlight here is the redeclaration of the interface in the inherited child. By default, letting B inherit from A already makes B inherit from the interface ITest so naturally people won't make B inherit from the interface ITest again. And that is not enough. If you want to overwrite the method in base, you have to redeclare the same interface that the method inherits from. – TDao Sep 17 '21 at 14:39
0

In the case you are inheriting from a non-derived class, you could simply create an abstract super class and inherit from it downstream instead.

0

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)?

You cannot override a non-virtual method. However you can use the new modifier keyword to get similar results:

class Class0
{
    public int Test()
    {
        return 0;
    }
}

class Class1 : Class0
{
    public new int Test()
    {
        return 1;
    }
}
. . .
// result of 1
Console.WriteLine(new Class1().Test());

You will also want to make sure that the access modifier is also the same, otherwise you will not get inheritance down the line. If another class inherits from Class1 the new keyword in Class1 will not affect objects inheriting from it, unless the access modifier is the same.

If the access modifier is not the same:

class Class0
{
    protected int Test()
    {
        return 0;
    }
}

class Class1 : Class0
{
    // different access modifier
    new int Test()
    {
        return 1;
    }
}

class Class2 : Class1
{
    public int Result()
    {
        return Test();
    }
}
. . .
// result of 0
Console.WriteLine(new Class2().Result());

...versus if the access modifier is the same:

class Class0
{
    protected int Test()
    {
        return 0;
    }
}

class Class1 : Class0
{
    // same access modifier
    protected new int Test()
    {
        return 1;
    }
}

class Class2 : Class1
{
    public int Result()
    {
        return Test();
    }
}
. . .
// result of 1
Console.WriteLine(new Class2().Result());

As pointed out in a previous answer, this is not a good design principle.

Aaron Thomas
  • 5,054
  • 8
  • 43
  • 89
0

The best answers sumerise the problem ("No, you cannot override a non-virtual method.")

I had a case where even non safe method only for non-production would help me a lot. But since I could not override method and could not change class since it was part of dll. My solution was to create extension method and use extension method instead of original Method/Property.

so:

class Base
{
     void Method()
     {
        ...
     }
}

static class BaseExtensions
{
     void ExtendedMethod(this Base base)
     {
          base.Method();
          ...
     }
}

I know it's not solution for everyone but it was enough for my problem.

-5

There is a way of achieving this using abstract class and abstract method.

Consider

Class Base
{
     void MethodToBeTested()
     {
        ...
     }

     void Method1()
     {
     }

     void Method2()
     {
     }

     ...
}

Now, if you wish to have different versions of method MethodToBeTested(), then change Class Base to an abstract class and method MethodToBeTested() as an abstract method

abstract Class Base
{

     abstract void MethodToBeTested();

     void Method1()
     {
     }

     void Method2()
     {
     }

     ...
}

With abstract void MethodToBeTested() comes an issue; the implementation is gone.

Hence create a class DefaultBaseImplementation : Base to have the default implementation.

And create another class UnitTestImplementation : Base to have unit test implementation.

With these 2 new classes, the base class functionality can be overridden.

Class DefaultBaseImplementation : Base    
{
    override void MethodToBeTested()    
    {    
        //Base (default) implementation goes here    
    }

}

Class UnitTestImplementation : Base
{

    override void MethodToBeTested()    
    {    
        //Unit test implementation goes here    
    }

}

Now you have 2 classes implementing (overriding) MethodToBeTested().

You can instantiate the (derived) class as required (i.e. either with base implementation or with unit test implementation).

slavoo
  • 5,798
  • 64
  • 37
  • 39
ShivanandSK
  • 649
  • 6
  • 13
  • @slavoo: Hi slavoo. Thanks for the code update. But could you please tell me the reason for downvoting this? – ShivanandSK Feb 25 '15 at 05:07
  • 7
    Because it doesn't answer the question. He's asking if you can override members not marked virtual. You've demonstrated that you have to implement members marked abstract. – Lee Louviere Apr 01 '15 at 20:09