【问题标题】:How to "properly" override a base class method?如何“正确”覆盖基类方法?
【发布时间】:2010-06-30 20:08:12
【问题描述】:

每当我重写基类的方法时,除了我对该方法的实现之外,我似乎有 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();
     }
}

我的问题是,子类如何知道(不查看基类实现)父类期望哪个顺序(或选项)? 有没有一种方法可以让父类强制所有派生类的三个替代项之一?

【问题讨论】:

  • PostViewManager, PreViewManager, CustomViewManager 继承自 ViewManager?如果是这样,您应该编辑代码。

标签: c# inheritance overriding


【解决方案1】:

子类如何知道(不看基类实现)父类期望哪个顺序(或选项)?

在子类化和覆盖方法时,无法“知道”这一点。正确的文档确实是这里唯一的选择。

有没有一种方法可以让父类强制所有派生类的三个替代项之一?

这里唯一的选择是避免这个问题。可以将其声明为非虚拟的,并在适当的位置调用虚拟方法,而不是允许子类覆盖该方法。例如,如果你想强制子类“首先调用你的版本”,你可以这样做:

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 解决方法(你也打败了我:),模板方法模式。您甚至可以将受保护的OnMethod 抽象化,以便派生类知道它们必须提供自己的实现,而且它们不必调用基本实现(假设它没有实例化 Base 是有意义的。
  • +1 这将使您免于受到其他开发人员的攻击。
  • @shambulator - 覆盖是可选的,因此它可能无法与使 OnMethod 抽象相媲美。不过,它仍然是一个不错的选择
  • 你的例子帮助我理解了我的问题...谢谢
  • @Dummy:如果你在子类中定义了一个同名的方法并且你没有更改为虚拟,那么你必须在子类中使用new关键字。此外,调用哪种方法取决于您转换为哪种类型。换句话说,您可以拥有var x = new SubClass(),在这种情况下((SubClass)x).Method() 将调用子类方法,而((BaseClass)x).Method() 将调用基类方法并完全跳过子类。这不允许在不更改现有代码以再次使用新类型的情况下进行扩展,因此它无法与virtual/override 相提并论。
【解决方案2】:

这就是为什么当你在库中发布虚拟方法时我觉得它们很危险。事实是,如果不查看基类,您永远不会真正知道,有时您必须启动反射器、阅读文档或通过反复试验来处理它。

在自己编写代码时,我总是厌倦遵循以下规则:

覆盖受保护虚方法的派生类不需要调用基类实现。即使未调用其实现,基类也必须继续正常工作。

这取自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 的基本调用。

所以,无论长短,它都会有所不同,不幸的是,没有立即知道的方法。如果我有疑问,我会一开始就省略这个电话。

【讨论】:

    【解决方案3】:

    简短的回答是否定的。您无法强制执行子调用基方法的顺序,或者根本调用它。

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

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

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

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

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

    这种方法很丑陋,需要大量额外的代码,所以我建议在文档中注明。

    【讨论】:

    • 我想知道 PostSharp 之类的东西是否可以强制执行该排序。
    【解决方案4】:

    库设计者应记录基类的要求。 这个问题是一些库主要包含密封类的原因。

    【讨论】:

      猜你喜欢
      • 2015-09-16
      • 1970-01-01
      • 2019-08-31
      • 1970-01-01
      • 2016-03-07
      • 2011-01-20
      • 1970-01-01
      • 2016-10-19
      • 1970-01-01
      相关资源
      最近更新 更多