简体   繁体   中英

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. 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:

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! 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. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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