156
// Cannot change source code
class Base
{
    public virtual void Say()
    {
        Console.WriteLine("Called from Base.");
    }
}

// Cannot change source code
class Derived : Base
{
    public override void Say()
    {
        Console.WriteLine("Called from Derived.");
        base.Say();
    }
}

class SpecialDerived : Derived
{
    public override void Say()
    {
        Console.WriteLine("Called from Special Derived.");
        base.Say();
    }
}

class Program
{
    static void Main(string[] args)
    {
        SpecialDerived sd = new SpecialDerived();
        sd.Say();
    }
}

The result is:

Called from Special Derived.
Called from Derived. /* this is not expected */
Called from Base.

How can I rewrite SpecialDerived class so that middle class "Derived"'s method is not called?

UPDATE: The reason why I want to inherit from Derived instead of Base is Derived class contains a lot of other implementations. Since I can't do base.base.method() here, I guess the best way is to do the following?

// Cannot change source code

class Derived : Base
{
    public override void Say()
    {
        CustomSay();

        base.Say();
    }

    protected virtual void CustomSay()
    {
        Console.WriteLine("Called from Derived.");
    }
}

class SpecialDerived : Derived
{
    /*
    public override void Say()
    {
        Console.WriteLine("Called from Special Derived.");
        base.Say();
    }
    */

    protected override void CustomSay()
    {
        Console.WriteLine("Called from Special Derived.");
    }
}
Michael Haddad
  • 4,085
  • 7
  • 42
  • 82
AZ.
  • 7,333
  • 6
  • 44
  • 62
  • Editing to match your update. – JoshJordan Feb 24 '10 at 04:39
  • possible duplicate of [How to call a second-level base class method like base.base.GetHashCode()](http://stackoverflow.com/questions/1006530/how-to-call-a-second-level-base-class-method-like-base-base-gethashcode) – nawfal May 02 '14 at 16:06
  • The way it works is as expected and how it should be. Also, your title is misleading. What you're really asking is "how to avoid calling base.base.method while still calling base.base.base.method?". – Jason Cheng May 13 '21 at 19:41

13 Answers13

134

Just want to add this here, since people still return to this question even after many time. Of course it's bad practice, but it's still possible (in principle) to do what author wants with:

class SpecialDerived : Derived
{
    public override void Say()
    {
        Console.WriteLine("Called from Special Derived.");
        var ptr = typeof(Base).GetMethod("Say").MethodHandle.GetFunctionPointer();            
        var baseSay = (Action)Activator.CreateInstance(typeof(Action), this, ptr);
        baseSay();            
    }
}
Evk
  • 98,527
  • 8
  • 141
  • 191
  • 71
    I really like this answer because the question wasn't whether or not it is recommended or whether or not it is a good idea, the question was whether or not there's a way to do it and if so what that way is. – Shavais Apr 09 '16 at 14:30
  • 7
    Especially useful when you have to deal with frameworks/libs lacking extensibility. By example, I had never needed to resort to such solutions for NHibernate which is highly extensible. But for dealing with Asp.Net Identity, Entity Framework, Asp.Net Mvc, I regularly ends up using such hacks for handling their missing features or hard coded behaviors unsuitable for my needs. – Frédéric Jul 20 '16 at 09:59
  • 4
    Thanks for that! I'd like to mention to the other people to stop quoting guidelines in response to a question. It was asked for a reason, not a scolding. If you don't know, then don't answer it! I'd also like to encourage everyone to blast the code-police so maybe it will discourage them from posting non-answers. If after answering a question, you feel compelled to quote guidelines, then go ahead and mention it. – DanW Dec 15 '17 at 16:17
  • 1
    What if we need the return value from the underlying function? – Perkins Sep 01 '18 at 03:59
  • 3
    Nevermind, figured it out. Cast to `Func` instead of `Action` – Perkins Sep 01 '18 at 04:14
  • 1
    Thanks. We all know that this sort of thing is bad juju, but sometimes you just need to do it because it's better than the alternative (rewriting someone's otherwise excellent library). – satnhak Oct 10 '18 at 12:08
  • In modding, it’s quite common to skip all architectural concerns because often it’s the only way to solve a problem. So I love this answer because it actually solves the problem. But be careful, I created the following issue that was just recently fixed and might not exist in your runtime (yet): https://github.com/mono/mono/issues/19964 – Andreas Pardeike Jul 10 '20 at 11:46
  • Perfect example of where we need this: Android requires derived view objects to call their base/parent/super method OnRestoreInstanceState. Apparently at the top of the hierarchy this registers somewhere. If it is not done, an exception is triggered. If you're deriving from a class (that you cannot change, but CAN override) with a faulty implementation of this method, you need to override and "bypass" your immediate parent but still need to call your "base.base" method. – Josh Sutterfield Jul 16 '20 at 23:17
  • Oddly, this approach ended up only calling the derived method again in my case. – Josh Sutterfield Jul 17 '20 at 00:06
102

This is a bad programming practice, and not allowed in C#. It's a bad programming practice because

  • The details of the grandbase are implementation details of the base; you shouldn't be relying on them. The base class is providing an abstraction overtop of the grandbase; you should be using that abstraction, not building a bypass to avoid it.

  • To illustrate a specific example of the previous point: if allowed, this pattern would be yet another way of making code susceptible to brittle-base-class failures. Suppose C derives from B which derives from A. Code in C uses base.base to call a method of A. Then the author of B realizes that they have put too much gear in class B, and a better approach is to make intermediate class B2 that derives from A, and B derives from B2. After that change, code in C is calling a method in B2, not in A, because C's author made an assumption that the implementation details of B, namely, that its direct base class is A, would never change. Many design decisions in C# are to mitigate the likelihood of various kinds of brittle base failures; the decision to make base.base illegal entirely prevents this particular flavour of that failure pattern.

  • You derived from your base because you like what it does and want to reuse and extend it. If you don't like what it does and want to work around it rather than work with it, then why did you derive from it in the first place? Derive from the grandbase yourself if that's the functionality you want to use and extend.

  • The base might require certain invariants for security or semantic consistency purposes that are maintained by the details of how the base uses the methods of the grandbase. Allowing a derived class of the base to skip the code that maintains those invariants could put the base into an inconsistent, corrupted state.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • 3
    On the topic of security, it should be noted that you cannot guarantee that callers will call the most-derived version of a virtual function. – rh. Feb 24 '10 at 18:06
  • 1
    @rh: yes, that is a good point. Hostile code does not need to obey the rules of C#. – Eric Lippert Feb 24 '10 at 18:27
  • 2
    @rh: In fact, it was worse before .NET 2.0; it used to be legal in IL to call overridden methods on a base class even if the calling class wasn't derived from it. See http://research.microsoft.com/en-us/um/people/akenn/sec/appsem-tcs.pdf for comments on how this and other IL/C# mismatches affect the security of C# code. – kvb Feb 24 '10 at 19:52
  • 1
    +1 OOP is meant exactly to reuse a basic behaviour from a base class. If one rather do what the base.base class does, then derive from it, instead of deriving from its derived. =) – Will Marcouiller Feb 25 '10 at 14:49
  • @kvb: Excellent point. In fact this change was make right before 2.0 shipped, and it broke verifiability of base calls in anonymous methods in C#. As you note, the verifier checks that the call site is *derived from* the type declaring the method; it does *not* check if the call site is *contained within* the type declaring the method! Fortunately the code generator now does the right thing, at long last, and we have eliminated the "base call is not verifiable" warning. – Eric Lippert Feb 25 '10 at 17:51
  • What if I don't know which functionality do I need (Base or GrandBase) until the run-time? We don't have any concept of run-time inheritance in c# – Haseeb Jadoon Dec 29 '15 at 13:13
  • 4
    @Jadoon: Then prefer composition to inheritance. Your class can take an instance of either Base or GrandBase, and the class can then defer functionality to the instance. – Eric Lippert Dec 29 '15 at 13:49
  • 4
    @BlackOverlord: Since you feel strongly on this topic, why not write an answer of your own to this seven-year-old question? That way we all get to benefit from your wisdom on this subject, and you would then have written *two* answers on StackOverflow, doubling your total contribution. That's a win-win. – Eric Lippert May 02 '17 at 20:26
  • 6
    @Eric Lippert: There are two reasons why i didn't write my own answer: first, i hadn't known how to do it, that why i found this topic. Second, there is a comprehensive answer by Evk down this page. – BlackOverlord May 02 '17 at 21:00
  • 4
    @DanW: I do know the answer; it is the first sentence of my answer: **the desired feature is not allowed in C# because it is a bad programming practice**. How do you do this in C#? **You don't.** The notion that I might not know the answer to this question is an amusing one, but we'll let that pass without further comment. Now, if you find this answer unsatisfying, why not write your own answer that you think does a better job? That way we all learn from your wisdom and experience, and you would also double the number of answers you've posted this year. – Eric Lippert Dec 15 '17 at 16:25
  • Sorry Eric, with the entire thread fresh in mind, it seemed obvious to me at the time that the comment was meant to pile on the main reply to this thread where nothing was said about how to actually do it, and not about your comment where you did actually give useful information... – DanW Dec 18 '17 at 10:43
  • 17
    @EricLippert what if base code is flawed and needs to be overridden like a 3rd party control? And the implementation includes a call to grandbase? For real world applications, it may be of critical nature and need hotfixing so waiting for the 3rd party vendor might not be an option. Bad practice vs reality of production environments. – Shiv Mar 01 '18 at 05:52
  • 1
    The problem is that the real world doesn't necessarily always conform to programming patterns and best practices. Re "you like what it does and want to reuse and extend it" - exactly, you like 95% of "what it does and want to reuse it", but you might not want to reuse that singular thing that happens when you call base.Method() – Alexander Gräf Mar 03 '23 at 19:45
24

You can't from C#. From IL, this is actually supported. You can do a non-virt call to any of your parent classes... but please don't. :)

rh.
  • 1,731
  • 1
  • 10
  • 11
10

The answer (which I know is not what you're looking for) is:

class SpecialDerived : Base
{
    public override void Say()
    {
        Console.WriteLine("Called from Special Derived.");
        base.Say();
    }
}

The truth is, you only have direct interaction with the class you inherit from. Think of that class as a layer - providing as much or as little of it or its parent's functionality as it desires to its derived classes.

EDIT:

Your edit works, but I think I would use something like this:

class Derived : Base
{
    protected bool _useBaseSay = false;

    public override void Say()
    {
        if(this._useBaseSay)
            base.Say();
        else
            Console.WriteLine("Called from Derived");
    }
}

Of course, in a real implementation, you might do something more like this for extensibility and maintainability:

class Derived : Base
{
    protected enum Mode
    {
        Standard,
        BaseFunctionality,
        Verbose
        //etc
    }

    protected Mode Mode
    {
        get; set;
    }

    public override void Say()
    {
        if(this.Mode == Mode.BaseFunctionality)
            base.Say();
        else
            Console.WriteLine("Called from Derived");
    }
}

Then, derived classes can control their parents' state appropriately.

JoshJordan
  • 12,676
  • 10
  • 53
  • 63
  • 3
    Why not just write a protected function in `Derived` which calls `Base.Say`, so that it can be called from `SpecialDerived`? Simpler, no? – nawfal May 02 '14 at 16:16
10

Why not simply cast the child class to a specific parent class and invoke the specific implementation then? This is a special case situation and a special case solution should be used. You will have to use the new keyword in the children methods though.

public class SuperBase
{
    public string Speak() { return "Blah in SuperBase"; }
}

public class Base : SuperBase
{
    public new string Speak() { return "Blah in Base"; }
}

public class Child : Base
{
    public new string Speak() { return "Blah in Child"; }
}

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        Child childObj = new Child();

        Console.WriteLine(childObj.Speak());

        // casting the child to parent first and then calling Speak()
        Console.WriteLine((childObj as Base).Speak()); 

        Console.WriteLine((childObj as SuperBase).Speak());
    }
}
Massimiliano Kraus
  • 3,638
  • 5
  • 27
  • 47
  • 2
    If you have an engine that can't know about base or child, and speak needs to work correctly when called by that engine, speak needs to be an override, not a new. If child needs 99% of base's functionality, but in the one speak case, it needs superbase's functionality... that's the kind of situation I understand the OP to be talking about, in which case this method won't work. It's not uncommon and the security concerns that have given rise to C#'s behaviour are commonly not really very concerning. – Shavais Apr 09 '16 at 14:46
  • Just a note in the case of controls and event call chains, the methods are often protected and hence not accessible like this. – Shiv Mar 01 '18 at 06:04
  • 3
    This isn't using inheritance, you may as well give each Speak an entirely unique name. – Nick Sotiros Mar 13 '18 at 22:23
  • yeah it is not 100% inheritance but it is using the interface from the parent – Kruczkowski Piotr Nov 14 '19 at 08:02
7
public class A
{
    public int i = 0;
    internal virtual void test()
    {
        Console.WriteLine("A test");
    }
}

public class B : A
{
    public new int i = 1;
    public new void test()
    {
        Console.WriteLine("B test");
    }
}

public class C : B
{
    public new int i = 2;
    public new void test()
    {
        Console.WriteLine("C test - ");
        (this as A).test(); 
    }
}
Pavel
  • 71
  • 1
  • 2
5

You can also make a simple function in first level derived class, to call grand base function

Rajesh
  • 51
  • 1
  • 1
  • 1
    Exactly so, and this preserves the whole abstraction scheme everyone's so worried about, and it highlights the way abstraction schemes are sometimes more trouble than they're worth. – Shavais Apr 09 '16 at 14:33
3

My 2c for this is to implement the functionality you require to be called in a toolkit class and call that from wherever you need:

// Util.cs
static class Util 
{
    static void DoSomething( FooBase foo ) {}
}

// FooBase.cs
class FooBase
{
    virtual void Do() { Util.DoSomething( this ); }
}


// FooDerived.cs
class FooDerived : FooBase
{
    override void Do() { ... }
}

// FooDerived2.cs
class FooDerived2 : FooDerived
{
    override void Do() { Util.DoSomething( this ); }
}

This does require some thought as to access privilege, you may need to add some internal accessor methods to facilitate the functionality.

Julian Gold
  • 1,246
  • 2
  • 19
  • 40
1

In cases where you do not have access to the derived class source, but need all the source of the derived class besides the current method, then I would recommended you should also do a derived class and call the implementation of the derived class.

Here is an example:

//No access to the source of the following classes
public class Base
{
     public virtual void method1(){ Console.WriteLine("In Base");}
}
public class Derived : Base
{
     public override void method1(){ Console.WriteLine("In Derived");}
     public void method2(){ Console.WriteLine("Some important method in Derived");}
}

//Here should go your classes
//First do your own derived class
public class MyDerived : Base
{         
}

//Then derive from the derived class 
//and call the bass class implementation via your derived class
public class specialDerived : Derived
{
     public override void method1()
     { 
          MyDerived md = new MyDerived();
          //This is actually the base.base class implementation
          MyDerived.method1();  
     }         
}
yoel halb
  • 12,188
  • 3
  • 57
  • 52
0

As can be seen from previous posts, one can argue that if class functionality needs to be circumvented then something is wrong in the class architecture. That might be true, but one cannot always restructure or refactor the class structure on a large mature project. The various levels of change management might be one problem, but to keep existing functionality operating the same after refactoring is not always a trivial task, especially if time constraints apply. On a mature project it can be quite an undertaking to keep various regression tests from passing after a code restructure; there are often obscure "oddities" that show up. We had a similar problem in some cases inherited functionality should not execute (or should perform something else). The approach we followed below, was to put the base code that need to be excluded in a separate virtual function. This function can then be overridden in the derived class and the functionality excluded or altered. In this example "Text 2" can be prevented from output in the derived class.

public class Base
{
    public virtual void Foo()
    {
        Console.WriteLine("Hello from Base");
    }
}

public class Derived : Base
{
    public override void Foo()
    {
        base.Foo();
        Console.WriteLine("Text 1");
        WriteText2Func();
        Console.WriteLine("Text 3");
    }

    protected virtual void WriteText2Func()
    {  
        Console.WriteLine("Text 2");  
    }
}

public class Special : Derived
{
    public override void WriteText2Func()
    {
        //WriteText2Func will write nothing when 
        //method Foo is called from class Special.
        //Also it can be modified to do something else.
    }
}
Massimiliano Kraus
  • 3,638
  • 5
  • 27
  • 47
Pierre
  • 11
  • 2
0

There seems to be a lot of these questions surrounding inheriting a member method from a Grandparent Class, overriding it in a second Class, then calling its method again from a Grandchild Class. Why not just inherit the grandparent's members down to the grandchildren?

class A
{
    private string mystring = "A";    
    public string Method1()
    {
        return mystring;
    }
}

class B : A
{
    // this inherits Method1() naturally
}

class C : B
{
    // this inherits Method1() naturally
}


string newstring = "";
A a = new A();
B b = new B();
C c = new C();
newstring = a.Method1();// returns "A"
newstring = b.Method1();// returns "A"
newstring = c.Method1();// returns "A"

Seems simple....the grandchild inherits the grandparents method here. Think about it.....that's how "Object" and its members like ToString() are inherited down to all classes in C#. I'm thinking Microsoft has not done a good job of explaining basic inheritance. There is too much focus on polymorphism and implementation. When I dig through their documentation there are no examples of this very basic idea. :(

Stokely
  • 12,444
  • 2
  • 35
  • 23
0

I had the same problem as the OP, where I only wanted to override a single method in the middle Class, leaving all other methods alone. My scenario was:

Class A - base class, DB access, uneditable.

Class B : A - "record type" specific functionality (editable, but only if backward compatible).

Class C : B - one particular field for one particular client.

I did very similar to the second part of the OP posting, except I put the base call into it's own method, which I called from from Say() method.

class Derived : Base
{
    public override void Say()
    {
        Console.WriteLine("Called from Derived.");

        BaseSay();
    }

    protected virtual void BaseSay()
    {
        base.Say();
    }
}

class SpecialDerived : Derived
{
    
    public override void Say()
    {
        Console.WriteLine("Called from Special Derived.");
        base.BaseSay();
    }
}

You could repeat this ad infinitum, giving, for example SpecialDerived a BaseBaseSay() method if you needed an ExtraSpecialDerived override to the SpecialDerived.

The best part of this is that if the Derived changes its inheritance from Base to Base2, all other overrides follow suit without needing changes.

-3

If you want to access to base class data you must use "this" keyword or you use this keyword as reference for class.

namespace thiskeyword
{
    class Program
    {
        static void Main(string[] args)
        {
            I i = new I();
            int res = i.m1();
            Console.WriteLine(res);
            Console.ReadLine();
        }
    }

    public class E
    {
        new public int x = 3;
    }

    public class F:E
    {
        new public int x = 5;
    }

    public class G:F
    {
        new public int x = 50;
    }

    public class H:G
    {
        new public int x = 20;
    }

    public class I:H
    {
        new public int x = 30;

        public int m1()
        {
           // (this as <classname >) will use for accessing data to base class

            int z = (this as I).x + base.x + (this as G).x + (this as F).x + (this as E).x; // base.x refer to H
            return z;
        }
    }
}
krlzlx
  • 5,752
  • 14
  • 47
  • 55