如何“正确”重写基类方法?

问题描述:

每当我重写一个基类的方法,除了我的这个方法的实现,我似乎有3个选择。如何“正确”重写基类方法?

1)调用base.Method(),然后提供我的实现。

2)提供我的实现,然后调用base.Method()

3)只需提供我的实现。

最近在使用库时,我已经意识到由于没有实现库所期望的方法而引入的一些错误。我不确定图书馆是否有问题,或者我的理解有问题。

我将举一个例子。

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(); 
    } 
} 

我的问题在这里怎么可能一个子类知道(不考虑看看基类实现)的顺序(或期权)是由父类的预期? 有没有一种方法可以让父类强制三个交替之一到所有的派生类?

+1

'PostViewManager','PreViewManager','CustomViewManager'继承自'ViewManager'?如果是这样,你应该编辑代码。 – LaTeX 2011-02-16 05:53:42

子类如何知道(无需查看基类实现)父类预期的顺序(或选项)?

当你继承和重写方法时,没有办法“知道”这个。正确的文档是这里唯一的选择。

有没有一种方法,其中父类可以强制三个交替之一到所有的派生类?

这里唯一的选择是避免这个问题。而不是让子类覆盖的方法,它可以声明非虚,并呼吁在适当的地方虚方法。例如,如果要强制执行的子类“先打电话给你的版本”,你可以这样做:

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

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

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

子类就可以“覆盖” OnMethod,并提供售后服务“方法”的工作出现这种情况的功能。

这是必需的原因是虚拟方法的设计允许子类完全替代父类的实现。这是有目的地完成的。如果您想防止这种情况,最好使该方法非虚拟化。

+1

你打败了我。这是脆弱的基类**问题。解决方法为+1(您也击败了我:),**模板方法模式**。您甚至可以创建受保护的'OnMethod'抽象,以便派生类知道它们*具有*提供它们自己的实现,而且它们不必调用基本实现(假设它没有意义实例化'Base')。 – shambulator 2010-06-30 20:18:12

+0

+1这可以帮助您避免开发人员的冲突。 – Marc 2010-06-30 20:23:18

+0

@shambulator - Override是可选的,所以它可能无法与'OnMethod'抽象相提并论。它仍然是一个不错的选择,虽然 – 2010-06-30 20:24:42

简短的回答是否定的。你不能以孩子调用基本方法的顺序执行,或者根本不调用它。

从技术上讲,这些信息应该包含在基础对象的文档中。如果您绝对必须在子类的代码之前或之后运行一些代码,则可以执行以下操作:

1)在基类中创建一个非虚函数。我们称之为MyFunction

2)在基类中创建一个受保护的虚函数。我们称之为_MyFunction

3)派生类扩展了_MyFunction方法。

4)让MyFunction调用_MyFunction并在调用它之前或之后运行它需要运行的代码。

这种方法是丑陋的,将需要大量的额外的代码,所以我建议只是把通知的文件中。

+0

我不知道像PostSharp这样的东西是否可以强制执行该命令。 – FrustratedWithFormsDesigner 2010-06-30 20:14:48

基本类的需求应该由库设计者记录。 这个问题就是为什么一些库包含主要密封类的原因。

这就是为什么我觉得虚拟方法是危险的,当你把它们放在图书馆。事实是,如果不查看基类,你永远不会知道,有时你必须启动反射器,阅读文档或通过反复试验来处理它。

在编写代码时我自己,我一直累到遵循说规则:

重写受保护的虚方法

派生类不需要调用基类的实现。即使未调用其实现,基类也必须继续正常工作。

这取自http://msdn.microsoft.com/en-us/library/ms229011.aspx,但是这是用于事件设计,但我相信我在框架设计指南书(http://www.amazon.com/Framework-Design-Guidelines-Conventions-Libraries/dp/0321246756)中阅读了此内容。

但是,这显然是不正确的,例如,ASP.NET Web窗体需要在Page_Load上进行基址调用。

所以,总之,它会变化,不幸的是没有即时的知道方式。如果我有疑问,我会最初省略电话。

+0

多么美妙的答案。我的确切想法。上投票。 – Xtro 2017-11-25 23:32:24