【问题标题】:Make sure base method gets called in C#确保在 C# 中调用基本方法
【发布时间】:2011-02-26 01:44:18
【问题描述】:

我能否以某种方式强制派生类始终调用被覆盖的方法基类?

public class BaseClass
{
    public virtual void Update()
    {
        if(condition)
        {
            throw new Exception("..."); // Prevent derived method to be called
        }
    }
}

然后在派生类中:

public override void Update()
{
    base.Update(); // Forced call

    // Do any work
}

我搜索并找到了使用非虚拟 Update() 以及受保护虚拟 UpdateEx() 的建议。就是感觉不是很整洁,有没有更好的办法?

我希望你能得到这个问题,我很抱歉英语不好。

【问题讨论】:

    标签: c# inheritance overriding base


    【解决方案1】:

    使用template method pattern - 不要覆盖需要做一些工作的基方法,覆盖一个特定的位,它可以是抽象的,也可以是基类中的无操作。 (关于是使其成为无操作还是抽象的决定通常是相当明显的 - 基类本身是否有意义,作为一个具体类?)

    听起来这基本上是您在 UpdateEx 中找到的模式 - 尽管它通常是 UpdateImpl 或在我的经验中类似的东西。在我看来,这作为一种模式没有任何问题 - 它避免了强制所有派生类编写相同代码来调用基方法的任何想法。

    【讨论】:

    • 虽然我同意模板方法模式通常更可取,但应该注意的是,BCL 大量使用了“覆盖必须调用基类方法”(反?)模式。 Windows 窗体类尤其如此。
    • 如果您有两层深的层次结构,您仍希望在所有层级上强制进行碱基调用,这是否意味着您获得了UpdateImpl2
    • @DirkBoer:你的意思是如果所有“孙子”类最终都应该调用三个方法?如果是这样,那么是的,类似的东西 - 但我会尝试在那时简化设计。
    • 你可能是对的。也许 OnCreate 事件或类似的事情更有意义。感谢您的快速回答!
    • 有了这个,基方法和子方法的调用顺序就很容易控制了,这是IMO的另一个加分项。
    【解决方案2】:

    我花了一点时间才弄明白 Update 和 UpdateEx 的样子。这是一个可能对其他人有所帮助的代码示例。

    public class BaseClass
    {
        // This is the Update that class instances will use, it's never overridden by a subclass
        public void Update()
        {
            if(condition);
            // etc... base class code that will always run
    
            UpdateEx(); // ensure subclass Update() functionality is run
        }
    
        protected virtual void UpdateEx()
        {
            // does nothing unless sub-class overrides
        }
    }
    

    子类永远不会有 Update() 的任何实现。它将使用 UpdateEx() 将实现添加到 Update();

    public class ConcreteClass : BaseClass
    {
        protected override void UpdateEx()
        {
            // implementation to be added to the BaseClass Update();
        }
    }
    

    ConcreteClass 的任何实例都将使用 Update() 的 BaseClass 实现,但 ConcreteClass 使用 UpdateEx() 对其进行扩展。

    【讨论】:

      【解决方案3】:

      我认为你找到的建议很好。

      基类构造函数中唯一不能避免从子类调用的基类方法。

      【讨论】:

        【解决方案4】:

        我认为拥有一个调用可以扩展的虚拟“钩子”的非虚拟基成员是此类问题的最常见解决方案。

        根据您的用例,您可能希望改用event,但实现事件的通常模式是拥有一个虚拟的OnEvent 方法,子类可以覆盖而不是添加事件处理程序,所以在您的示例案例归结为同一件事。

        【讨论】:

          猜你喜欢
          • 2019-12-06
          • 2023-03-08
          • 1970-01-01
          • 2011-10-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多