base.Method() with multiple levels of inheritance not being called?

helios picture helios · May 4, 2013 · Viewed 9k times · Source

I've searched and not been able to find any solution to my problem. My scenario is very simple:

public class A
{
    public virtual void MethodOne()
    {
       Console.log( "A" ); 
    }
}

public class B : A
{
    public override void MethodOne()
    {
        base.MethodOne();
        Console.log( "B" );
    }
}

public class C : B
{
    public override void MethodOne()
    {
        base.MethodOne();
        Console.log( "C" );
    }
}

What I am trying to do is have an instance of class C (we'll name it 'instanceC') call both the overridden method of its parent, and its grandparent. So I'd expect this:

instanceC.MethodOne();
// Output:
// "A"
// "B"
// "C"

But instead am getting this:

instanceC.MethodOne();
// Output
// "A"
// "C"

with class B's method being skipped over. Is this not possible? I thought this is the whole point of inheritance/polymorphism. Thanks in advance!

Answer

Steven Wexler picture Steven Wexler · May 4, 2013

Your example works as expected for me. I see A B C. I think your most likely issue is that C doesn't extend B. However, let me suggest an arguably safer pattern while we're on the subject. You seem to want all overrides of MethodOne to execute code from their base classes. Great, inheritance is a good pattern for this. However, with this pattern you cannot force inheritors to execute the base logic because you cannot force them to call base.MethodOne(). Even if they do callbase.MethodOne(), you cannot ensure the order of the logic. Will they call base.MethodOne() at the beginning of the method, middle of the method, or end of the method? Often, in these types of patterns you want sub classes to execute all the base logic at the beginning of the function. The following pattern forces inheritors to execute base logic in the order base classes expect. It's technically less flexible but safer because inheritors must extend the base classes in a way that the base classes specify.

public class A
{
    //Don't make this method virtual because you don't actually want inheritors 
    //to be able to override this functionality.  Instead, you want inheritors
    //to be able to append to this functionality.
    public void MethodOne()
    {
        Console.WriteLine( "A" ); 
        MethodToBeOverriddenOne();
    }
    //Expose a place where inheritors can add extra functionality
    protected virtual void MethodToBeOverriddenOne() { }      
}

public class B : A
{
    //Seal the method because you don't actually want inheritors 
    //to be able to override this functionality.  Instead, you want inheritors
    //to be able to append to this functionality.
    protected sealed override void MethodToBeOverriddenOne()
    {
        Console.WriteLine("B");
        MethodToBeOverriddenTwo();
    }
    //Expose a place where inheritors can add extra functionality
    protected virtual void MethodToBeOverriddenTwo() { }  
}

public class C : B
{
    protected sealed override void MethodToBeOverriddenTwo()
    {
        Console.WriteLine("C");
    }
}