我希望有一个在基类中定义的字段,它将影响属于基类的对象的创建。但是,我希望能够覆盖字段的值,之前调用基类cto&r; r。一个例子:
class ObjNeedParam
{
public ObjNeedParam(int p)
{
val = p;
}
int val;
int Value{get{return Value;}}
}
class Base
{
public Base()
{
obj = new ObjNeedParam(paramVal);
}
ObjNeedParam obj;
protected int paramVal = 1;
}
class Derived : Base
{
public Derived()
{
//Once I'm here, obj has already been created with paramVal=1 instead of 2!
dummy = 3;
}
new int paramVal = 2;
int dummy;
}
答案 0 :(得分:3)
这种做法有点值得怀疑,所以你可能想在这里重新考虑你的方法。
如果您仍想继续这样做,正确的方法是使用virtual
方法将此值提供给基础构造函数:
class Base
{
public Base()
{
obj = new ObjNeedParam(GetParamVal());
}
protected virtual int GetParamVal() { return 1; }
}
class Derived : Base
{
protected override int GetParamVal() { return 2; }
}
您必须确保override
不使用在Derived
的构造函数中初始化的Derived
的任何类成员,因为该构造函数将在调用覆盖的点上还没有运行!请参阅Virtual member call in a constructor。
更新:这有点值得怀疑,因为在构造某个派生类型的对象时,编译器有一个问题需要解决:字段应该以什么顺序初始化并且构造函数运行以便任何方法调用从任何构造函数内部保证找到处于“可用”状态的对象?
这个问题在一般情况下无法解决,因为根据定义,在所有构造函数都返回之前,对象不处于可用状态,我们讨论的是从里面调用这些构造函数的方法。所以编译器必须尽可能多地保证,并阻止或允许你做一些不可靠安全的事情。
在这种情况下,C ++(有趣地)阻止了做不可证明安全的事情,而C#允许它。因此,它有点值得怀疑,因为如果你不注意,就有可能引入bug。更安全的方法是编写类,以便在构造函数运行后初始化该成员。
答案 1 :(得分:1)
您需要做的是不以这种方式初始化字段。另一种方法是使字段成为属性,并允许子类覆盖。或者,允许通过参数在基类构造函数中设置字段,因此您可以编写如下代码:
class Base
{
public Base() : this(1)
{
}
public Base(int param)
{
paramVal = param;
}
private int paramVal;
}
class Derived : Base
{
public Derived() : base(2)
{
}
}
最终,字段通常是私有到一个类,并且永远不会被派生类重写。如果要为派生类公开它以进行操作,那么您可能需要除字段之外的其他内容。