How to “properly” override a base class method?

2020-02-18 05:50发布

Whenever i override a method of a base class, other than my implementation of this method, i seem to have 3 choices.

1) Call base.Method(), and then provide my implementation.

2) Provide my implementation and then call base.Method()

3) Just provide my implementation.

Recently while using a library i have realized few bugs that were introduced because of not implementing the method as expected by the library. I am not sure if that is bad on part of library, or something wrong in my understanding.

I will take one example.

public class ViewManager {
     public virtual void Customize(){
        PrepareBaseView();
     }
}

public class PostViewManager {
     public override void Customize(){
        base.Customize();
        PreparePostView();
     }
}


public class PreViewManager {
     public override void Customize(){
        PreparePreView();
        base.Customize();
     }
}


public class CustomViewManager {
     public override void Customize(){
        PrepareCustomView();
     }
}

My question here is that how could a child class know (without taking a look at base class implementation) which order (or option) is being expected by the parent class? Is there a way in which parent class could enforce one of the three alternates to all the deriving classes?

4条回答
劳资没心,怎么记你
2楼-- · 2020-02-18 06:08

how could a child class know (without taking a look at base class implementation) which order (or option) is being expected by the parent class?

There is no way to "know" this when you are subclassing and overriding a method. Proper documentation is really the only option here.

Is there a way in which parent class could enforce one of the three alternates to all the deriving classes?

The only option here is to avoid the issue. Instead of allowing the subclass to override the method, it can be declared non-virtual, and call a virtual method in the appropriate place. For example, if you want to enforce that subclasses "call your version first", you could do:

public class BaseClass {
    public void Method() // Non-virtual
    {
          // Do required work

          // Call virtual method now...
          this.OnMethod();
    }

    protected virtual void OnMethod()
    { // Do nothing
    }
 }

The subclasses can then "override" OnMethod, and provide functionality that happens after "method"'s work.

The reason this is required is that virtual methods are designed to allow a subclass to completely replace the implementation of the parent class. This is done on purpose. If you want to prevent this, it's better to make the method non-virtual.

查看更多
走好不送
3楼-- · 2020-02-18 06:29

The requirements of the base class should be documented by the library designer. This issue is the reason why some libraries contain mainly sealed classes.

查看更多
冷血范
4楼-- · 2020-02-18 06:30

This is why I feel virtual methods are dangerous when you ship them in a library. The truth is you never really know without looking at the base class, sometimes you have to fire up reflektor, read documentation or approach it with trial and error.

When writing code myself I've always tired to follow the rule that says:

Derived classes that override the protected virtual method are not required to call the base class implementation. The base class must continue to work correctly even if its implementation is not called.

This is taken from http://msdn.microsoft.com/en-us/library/ms229011.aspx, however this is for Event design though I believe I read this in the Framework Design Guidelines book (http://www.amazon.com/Framework-Design-Guidelines-Conventions-Libraries/dp/0321246756).

However, this is obviously not true, ASP.NET web forms for example require a base call on Page_Load.

So, long and short, it varies and unfortunately there is no instant way of knowing. If I'm in doubt I will omit the call initially.

查看更多
萌系小妹纸
5楼-- · 2020-02-18 06:30

The short answer is no. You can't enforce in what order the child calls the base method, or if it calls it at all.

Technically this information should be included in the base object's documentation. If you absolutely must have some code run before or after the child class' code than you can do the following:

1) Create a non-virtual function in the base class. Let's call it MyFunction

2) Create a protected virtual function in the base class. Let's call it _MyFunction

3) Have deriving classes extend the _MyFunction method.

4) Have MyFunction call _MyFunction and run the code it needs to run before or after calling it.

This method is ugly and would require a lot of extra code, so I recommend just putting a notice in the documentation.

查看更多
登录 后发表回答