Search code examples
c#winformswinapioverridingradix

C# - when to call base.OnSomething?


I'm using Windows.Forms and have to inherit some controls to provide custom behavior. This inheritance obviously leads to method overriding.

So, here is the question - in which cases the order of calling base.OnSomething(...) can really affect the visible behavior of your program?

protected override OnRetrieveVirtualItem(RetrieveVirtualItemEventArgs e)
{
    // base.OnRetrieveVirtualItem(e); - Could this potentially break something?

    // Perform your custom method.
    // ...

    base.OnRetrieveVirtualItem(e); // Is this always "correct"?
}

As far as I know for know, this order can be important when overriding paint-related methods (OnDrawItem, ...), but I guess there are some other ways to shoot yourself in the leg, because Windows.Forms does a lot of unmanaged code calls with possible side effects.

So, when could it possibly matter? And what are the rules of thumb about choosing the correct place to call the base method in these cases?


Solution

  • You only need to call the base.SomeVirtualMethod when the documentation for that API specifies you should do so. Otherwise, it should be implied as optional. API's that require you to call the base method, but do not explicitly state so, are badly designed.

    The reason requiring a base call is poor design, is because you can never expect what someone overriding your method will do, and you cannot be certain they will call the base method to execute any required or critical code.

    So in short, refer to the documentation, otherwise no it is usually not necessary. The .NET Framework was designed by such guidelines, most virtual methods don't require a call to the base for these reasons. The ones that do are documented.

    Thanks to roken who pointed out a very important reason to call base virtual methods, is when using events. However, my counter argument that this is not always the case still applies, especially if you are using third party libraries or classes that don't follow the .NET idiom and patterns, there just isn't any certainty. Take this example.

    namespace ConsoleApplication12
    {
        using System;
        using System.Diagnostics;
    
        class Foo
        {
            public Foo() {
            }
    
            public event EventHandler Load;
    
            protected virtual void OnLoad() {
                EventHandler handler = Load;
    
                if (handler != null) {
                    handler(this, new EventArgs());
                }
    
                Debug.WriteLine("Invoked Foo.OnLoad");
            }
    
            public void Run() {
                OnLoad();
            }
        }
    
        class DerivedFoo : Foo
        {
            protected override void OnLoad() {
                base.OnLoad();
                Debug.WriteLine("Invoked DerivedFoo.OnLoad");
            }
        }
    
        class Program
        {
            static void Main(string[] args) {
                DerivedFoo dFoo = new DerivedFoo();
    
                dFoo.Load += (sender, e) => {
                    Debug.WriteLine("Invoked dFoo.Load subscription");    
                };
    
                dFoo.Run();
            }
        }
    }
    

    If you run this example, you will get three invocations to Foo.OnLoad, DerivedFoo.OnLoad, and the event subscription dFoo.Load. If you comment out the call to base.OnLoad in DerivedFoo, you will now only get a single invocation to DerivedFoo.OnLoad, and the base and subscriber did not get called.

    The point is still strong that its up to documentation. There is still no certainty that a base virtual method implementation invokes its subscribers. So that should be clear. Luckily the .NET Framework is extremely consistant to the .NET event model thanks to the framework designers, but I still cannot stress enough to always read the documentation for the API.

    It comes into play a lot when you're not dealing with events at all, but things like abstract base classes. How do you know whether to call a base event for an abstract class? Does the abstract class provide a default implementation, or does it expect you to provide it?

    Documentation is the strongest, clearest way to define a contract for a virtual member. This is one reason why the .NET framework designer team generally provides at least a single concrete implementation for an abstract class that gets shipped.

    I think that Krzysztof Cwalina says it best in the framework design guidelines.

    A common question I get is whether documentation for virtual members should say that the overrides must call the base implementation. The answer is that overrides should preserve the contract of the base class. They can do it by calling the base implementation or by some other means. It is rare that a member can claim that the only way to preserve its contract (in the override) is to call it. In a lot of cases, calling the base might be the easiest way to preserve the contract (and docs should point that out), but it's rarely absolutely required.

    And I agree completely. In the case you override a base implementation and decide not to call it, you should provide the same functionality.

    I hope this clears up some confusion I had in the comments.