Object-Oriented Design – Should Override Methods Call Base Method?

object-oriented-design

I'm just running NDepend against some code that I have written and one of the warnings is Overrides of Method() should call base.Method().

The places this occurs are where I have a base class which has virtual properties and methods with default behaviour but which can be overridden by a class which inherits from the base class and doesn't call the overridden method.

For example, in the base class I have a property defined like this:

protected virtual char CloseQuote
{
    get
    {
        return '"';
    }
}

And then in an inheriting class which uses a different close quote:

protected override char CloseQuote
{
    get
    {
        return ']';
    }
}

Not all classes which inherit from the base class use different quote characters hence my initial design.

The alternatives I thought of were have get/set properties in the base class with the defaults set in the constructor:

protected BaseClass()
{
    this.CloseQuote = '"';
}

protected char CloseQuote { get; set; }

public InheritingClass()
{
    this.CloseQuote = ']';
}

Or make the base class require the values as constructor args:

protected BaseClass(char closeQuote, ...)
{
    this.CloseQuote = '"';
}

protected char CloseQuote { get; private set; }

public InheritingClass()
    base (closeQuote: ']', ...)
{
}

Should I use virtual in a scenario where the base implementation may be replaced instead of extended or should I opt for one of the alternatives I thought of? If so, which would be preferable and why?

Best Answer

It is a valid design decision to have a default implementation of a method in a base-class that should be completely replaced when the method is overridden in a derived class.

Thus, you could regard the warnings from NDepend as a false-positive for your code. I would check the NDepend documentation to see if there is an option or source-code annotation that tells NDepend that not calling the base-class implementation is correct here to get rid of the clutter.

If there is no such option (or it does not work for properties), my preference would be the first alternative (overriding the value of CloseQuote in the derived-class' constructor).