c# - 如何避免从基类构造函数调用虚方法

标签 c# inheritance constructor virtual-functions

我在库中有一个抽象类。我正在努力使其尽可能容易地正确实现此类的派生。问题是我需要分三步初始化对象:抓取一个文件,执行一些中间步骤,然后使用该文件。第一步和最后一步是特定于派生类的。这是一个精简的示例。

abstract class Base
{
    // grabs a resource file specified by the implementing class
    protected abstract void InitilaizationStep1();

    // performs some simple-but-subtle boilerplate stuff
    private void InitilaizationStep2() { return; }

    // works with the resource file
    protected abstract void InitilaizationStep3();

    protected Base()
    {
        InitilaizationStep1();
        InitilaizationStep2();
        InitilaizationStep3();
    }
}

麻烦的当然是构造函数中的虚方法调用了。如果库的使用者不能指望派生类被完全初始化,恐怕他们会发现自己在使用类时受到限制。

我可以将构造函数中的逻辑提取到 protected Initialize() 方法中,但随后实现者可能会调用 Step1()Step3() 而不是直接调用 Initialize()。问题的症结在于,如果跳过Step2(),就不会出现明显的错误;只是在某些情况下表现糟糕。

我觉得无论哪种方式都存在严重且不明显的“陷阱”,图书馆的 future 用户将不得不解决这个问题。我应该使用其他设计来实现这种初始化吗?

如有必要,我可以提供更多详细信息;我只是想提供最简单的例子来表达问题。

最佳答案

我会考虑创建一个 abstract factory负责使用 template method 实例化和初始化派生类的实例用于初始化。

举个例子:

public abstract class Widget
{
    protected abstract void InitializeStep1();
    protected abstract void InitializeStep2();
    protected abstract void InitializeStep3();

    protected internal void Initialize()
    {
        InitializeStep1();
        InitializeStep2();
        InitializeStep3();
    }

    protected Widget() { }
}

public static class WidgetFactory
{
    public static CreateWidget<T>() where T : Widget, new()
    {
        T newWidget = new T();
        newWidget.Initialize();
        return newWidget;
    }
}

// consumer code...
var someWidget = WidgetFactory.CreateWidget<DerivedWidget>();

此工厂代码可以得到显着改进 - 特别是如果您愿意使用 IoC 容器来处理此职责...

如果您无法控制派生类,您可能无法阻止它们提供可调用的公共(public)构造函数 - 但至少您可以建立消费者可以遵守的使用模式。

并不总是可以防止您的类的用户搬起石头砸自己的脚 - 但是,您可以提供基础设施来帮助消费者在熟悉设计后正确使用您的代码。

关于c# - 如何避免从基类构造函数调用虚方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1155305/

相关文章:

c# - 通过将可变大小的字符串传递给它来从 C# 调用 C++ 函数

c# - 无法在 C# 资源文件中插入 unicode 符号

c# - 在 C++ 和 C# 中使用 try/catch 的正确方法是什么?

c++ - 派生和破坏封装,还是违反 DRY?

java - Sonar 问题 : "Overide the "equals"method in this class

c++ - 如何继承模板函数?

c++ - 放置类构造函数

java - 如何使用 easymock 模拟构造函数上的方法调用?

javascript - 构造函数没有保存 querySelector(x).value

c# - 如何将razor生成的html变成字符串?