小编典典

在基类构造函数中调用虚拟方法

c#

我知道从基类构造函数调用虚拟方法可能很危险,因为子类可能未处于有效状态。(至少在C#中)

我的问题是,如果虚拟方法是初始化对象状态的方法,那该怎么办?是好的做法还是应该分两步进行:首先创建对象,然后加载状态?

第一种选择:(使用构造函数初始化状态)

public class BaseObject {
    public BaseObject(XElement definition) {
        this.LoadState(definition);
    }

    protected abstract LoadState(XElement definition);
}

第二种选择:(使用两步过程)

public class BaseObject {
    public void LoadState(XElement definition) {
        this.LoadStateCore(definition);
    }

    protected abstract LoadStateCore(XElement definition);
}

在第一种方法中,代码的使用者可以使用一个语句创建和初始化对象:

// The base class will call the virtual method to load the state.
ChildObject o = new ChildObject(definition)

在第二种方法中,使用者必须创建对象,然后加载状态:

ChildObject o = new ChildObject();
o.LoadState(definition);

阅读 280

收藏
2020-05-19

共1个答案

小编典典

(此答案适用于C#和Java。我相信C ++在此问题上的工作方式有所不同。)

在构造函数中调用虚拟方法确实很危险,但有时最终会得到最干净的代码。

我会尽量避免在可能的情况,但没有弯曲的设计 巨大 。(例如,“初始化之后”选项禁止不变性。)如果你 在构造函数中使用虚拟方法,文件就 非常
强烈。只要每个参与人员都知道它在做什么,就不会引起 太多 问题。但是,正如您在第一个示例中所做的那样,我将尝试限制可见性。

编辑:这里很重要的一件事是C#和Java之间的初始化顺序有所不同。如果您有以下课程:

public class Child : Parent
{
    private int foo = 10;

    protected override void ShowFoo()
    {
        Console.WriteLine(foo);
    }
}

where the Parent constructor calls ShowFoo, in C# it will display 10. The
equivalent program in Java would display 0.

2020-05-19