强制子类在计算后初始化父属性

Sma*_*n2k 5 c# oop

我有一个Bicycle继承自的子类Agent.代理人具有依赖于自行车来定义它的属性.也就是说,代理的物理模型需要用速度和加速度约束来初始化,速度和加速度约束是基于每个自行车定义的,并且对于另一种类型的代理将是不同的.

我遇到的问题是我无法在base()构造函数中传递我需要计算的参数(速度/加速度需要计算以从理论分布中绘制它们),因为子类当然还没有被实例化.

每个自行车实例进行一次计算,但是多次使用,因此简单的静态方法无法完成工作.我可以protected在计算后调用父方法中的一个方法,但AFAIK无法在孩子中强制执行此方法,或者更具体地说,在我将来可能不写的任何孩子中.

例如,我可以:

public abstract class Agent
{
    protected IPhysics PluginPhysics { get; set; }

    protected Agent(...)
    {
    }
}

public class Bicycle : Agent
{
    private double maxA;

    public Bicycle(Object anotherParameter) : base(...)
    {
        maxA = ComputationOfMaxA();
        this.PluginPhysics = new Physics(anotherParameter, maxA);
    }

    private static double ComputationOfMaxA()
    {
       ...
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)

或者我可以:

public abstract class Agent
{
    protected IPhysics PluginPhysics { get; private set; }

    protected Agent(...)
    {
    }

    protected void SetupPhysics(Physics physics)
    {
        this.PluginPhysics = physics;
    }
}

public class Bicycle : Agent
{
    private double maxA;

    public Bicycle(Object anotherParameter) : base(...)
    {
        maxA = ComputationOfMaxA();
        SetupPhysics(new Physics(anotherParameter,maxA));
    }

    private static double ComputationOfMaxA()
    {
       ...
    }

    ...
}
Run Code Online (Sandbox Code Playgroud)

我宁愿不做其中任何一个,因为没有编译时的方法来确保孩子初始化PluginPhysics我能想到的,而且我宁愿PluginPhysics一旦初始化就无法改变.我还宁愿没有需要进入类Physics外的参数部分Bicycle.我很欣赏所有这些事情可能无法同时实现.

在调用任何相关的类对象之前,如果缺少强有力的文档或父类中的一堆运行时空检查,是否存在一种明显的C#-ish方式,我错过了强迫孩子初始化父项使用前的类字段,如果你不能在构造函数中做到这一点?

Sco*_*ain 3

d4Rk 的答案 非常接近,但是您应该尝试不要从构造函数调用虚拟方法,因为可能会发生不好的事情。但是,如果您使用延迟加载技巧的组合,则ISupportInitialize可以将插件的创建推迟到构造函数完成之后。

public abstract class Agent : ISupportInitialize
{
    private bool _initialized = false;

    private IPhysics _pluginPhysics;
    protected IPhysics PluginPhysics 
    { 
        get
        {
            if(!_initialized)
                EndInit();
            return _pluginPhysics;
        }
    }

    protected Agent(...)
    {
    }

    protected abstract IPhysics CreatePhysics();

    ISupportInitialize.BeginInit()
    {
       //We make this a explicit implementation because it will not
       //do anything so we don't need to expose it.
    }

    public void EndInit()
    {
        if(_initialized)
            return;

        _initialized = true;
        _pluginPhysics = CreatePhysics();
    }
}

public class Bicycle : Agent
{
    private double maxA;
    Object _anotherParameter;

    public Bicycle(Object anotherParameter)
    {
        _anotherParameter = anotherParameter;
    }
    protected override IPhysics CreatePhysics()
    {
        ComputationOfMaxA();
        return new Physics(anotherParameter, maxA);
    }
}
Run Code Online (Sandbox Code Playgroud)

EndInit()类的用户在获取对象后需要调用以导致IPhysics对象被创建,但是如果他们忘记调用初始化函数,物理对象上的 getter 将在第一次使用时触发初始化调用本身。

您可以在没有接口的情况下执行我所展示的所有ISupportInitialize操作,而只需在基类上使用公共Initalize()方法,但我喜欢在合适时公开框架接口。