简体   繁体   English

在C#的基类中使用派生类的字段

[英]use a derived class's field in the base class in c#

I want to have a field, defined in a base class, that will affect the creation of an object belonging to the base class. 我想要一个在基类中定义的字段,该字段将影响属于基类的对象的创建。 However, I want to be able to override the value of the field, before the Base class cto'r is called. 但是,我希望能够在调用基类cto'r 之前覆盖该字段的值。 An example: 一个例子:

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;
}

This practice is somewhat questionable, so you might want to rethink your approach here. 这种做法有些可疑,因此您可能要在这里重新考虑您的方法。

If you still want to go ahead with this, the correct way is to have a virtual method that provides this value to the base constructor: 如果您仍然想继续进行此操作,则正确的方法是拥有一个向基本构造函数提供此值的virtual方法:

class Base
{
    public Base()
    {
        obj = new ObjNeedParam(GetParamVal());
    }

    protected virtual int GetParamVal() { return 1; }
}

class Derived : Base
{
    protected override int GetParamVal() { return 2; }
}

You will have to ensure that the override does not use any class members of Derived that get initialized in Derived 's constructor because that constructor will not have run yet at the point where the override is called! 你必须确保override不使用任何类成员Derived是怎么被初始化在Derived类的构造函数 ,因为它们的构造,但尚未在其中重写被称为点运行! See Virtual member call in a constructor . 请参见构造函数中的虚拟成员调用

Update: It is somewhat questionable because when constructing an object of some derived type the compiler has a problem to solve: in what order should the fields be initialized and the constructors run so that any method call from inside any constructor is guaranteed to find the object in a "usable" state? 更新:这有点可疑,因为在构造某种派生类型的对象时,编译器要解决一个问题:应以什么顺序初始化字段并以构造函数运行,以便保证从任何构造函数内部进行的任何方法调用都可以找到对象处于“可用”状态?

This problem cannot be solved in the general case because by definition the object is not in a usable state until all constructors have returned, and we are talking about calling methods from inside these constructors. 一般情况下无法解决此问题,因为根据定义,直到所有构造函数都返回后,对象才处于可用状态,并且我们正在谈论从这些构造函数内部调用方法。 So the compiler has to guarantee as much as it can and either prevent or allow you to do things that are not provably safe. 因此,编译器必须尽其所能保证,并阻止或允许您执行无法证明的安全措施。

In this scenario C++ (amusingly) prevents the doing of things that are not provably safe, while C# allows it. 在这种情况下,C ++(有趣的是)阻止了一些不安全的事情,而C#允许这样做。 Therefore it's somewhat questionable because if you don't pay attention it is possible to introduce bugs. 因此,这有点可疑,因为如果您不注意,可能会引入错误。 A safer approach would be to write the class such that this member is initialized after the constructors have run. 一种更安全的方法是编写此类,以便在构造函数运行后初始化此成员。

What you need to do is not initialise the field in that way. 您需要做的不是以这种方式初始化字段。 One alternative is to make the field a property, and allow overriding by the child class. 一种替代方法是将字段设置为属性,并允许子类进行覆盖。 Alternatively, allow the field to be set in the base class constructor via a parameter, so you can write code like this: 或者,允许通过参数在基类构造函数中设置字段,因此您可以编写如下代码:

class Base
{
    public Base() : this(1)
    {
    }

    public Base(int param)
    {
        paramVal = param;
    }

    private int paramVal;
}

class Derived : Base
{
    public Derived() : base(2)
    {   
    }
}

Ultimately, a field is typically private to a class, and is never overrideable by a derived class. 最终,字段通常是类的私有字段,并且不能被派生类覆盖。 If you want to expose it for a derived class to manipulate then you probably want something other than a field. 如果要公开它以便派生类进行操作,则可能需要除字段以外的其他内容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM