在基类构造函数中调用虚方法 [英] Calling virtual method in base class constructor
问题描述
我知道从基类构造函数调用虚方法可能很危险,因为子类可能未处于有效状态.(至少在 C# 中)
I know that calling a virtual method from a base class constructor can be dangerous since the child class might not be in a valid state. (at least in C#)
我的问题是,如果虚方法是初始化对象状态的方法呢?这是好的做法还是应该分两步走,首先创建对象,然后加载状态?
My question is what if the virtual method is the one who initializes the state of the object ? Is it good practice or should it be a two step process, first to create the object and then to load the state ?
第一个选项:(使用构造函数初始化状态)
First option: (using the constructor to initialize the state)
public class BaseObject {
public BaseObject(XElement definition) {
this.LoadState(definition);
}
protected abstract LoadState(XElement definition);
}
第二个选项:(使用两步过程)
Second option: (using a two step process)
public class BaseObject {
public void LoadState(XElement definition) {
this.LoadStateCore(definition);
}
protected abstract LoadStateCore(XElement definition);
}
在第一种方法中,代码的使用者可以用一条语句创建和初始化对象:
In the first method the consumer of the code can create and initialize the object with one statement:
// The base class will call the virtual method to load the state.
ChildObject o = new ChildObject(definition)
在第二种方法中,消费者必须创建对象,然后加载状态:
In the second method the consumer will have to create the object and then load the state:
ChildObject o = new ChildObject();
o.LoadState(definition);
推荐答案
(这个答案适用于 C# 和 Java.我相信 C++ 在这个问题上的工作方式不同.)
(This answer applies to C# and Java. I believe C++ works differently on this matter.)
在构造函数中调用虚方法确实很危险,但有时它可以得到最干净的代码.
Calling a virtual method in a constructor is indeed dangerous, but sometimes it can end up with the cleanest code.
我会尽量避免它,但不会极大地弯曲设计.(例如,稍后初始化"选项禁止不变性.)如果您确实在构造函数中使用虚拟方法,请非常强烈地记录它.只要涉及的每个人都知道它在做什么,就不应该造成太多的问题.不过,我会尝试限制可见性,就像您在第一个示例中所做的那样.
I would try to avoid it where possible, but without bending the design hugely. (For instance, the "initialize later" option prohibits immutability.) If you do use a virtual method in the constructor, document it very strongly. So long as everyone involved is aware of what it's doing, it shouldn't cause too many problems. I would try to limit the visibility though, as you've done in your first example.
这里很重要的一件事是 C# 和 Java 之间在初始化顺序上存在差异.如果您有一个类,例如:
One thing which is important here is that there's a difference between C# and Java in order of initialization. If you have a class such as:
public class Child : Parent
{
private int foo = 10;
protected override void ShowFoo()
{
Console.WriteLine(foo);
}
}
Parent
构造函数调用 ShowFoo
的地方,在 C# 中将显示 10.Java 中的等效程序将显示 0.
where the Parent
constructor calls ShowFoo
, in C# it will display 10. The equivalent program in Java would display 0.
这篇关于在基类构造函数中调用虚方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!