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

时间:2015-06-06 17:00:02

标签: 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()
    {
       ...
    }
    ...
}

或者我可以:

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()
    {
       ...
    }

    ...
}

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

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

3 个答案:

答案 0 :(得分:3)

d4Rk's answer非常接近,但是您应该尝试不将构造函数中的虚方法调用为bad things can happen。但是,如果您使用延迟加载技巧和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);
    }
}

你的类的用户需要在获得一个对象后调用EndInit()才能创建IPhysics对象,但是如果他们忘记调用初始化函数,那么物理上的getter对象将在第一次使用时触发初始化调用。

你可以在没有ISupportInitialize接口的情况下完成我所展示的所有内容,只在基类上使用公共Initalize()方法,但我喜欢在框架接口适合时公开它们。

答案 1 :(得分:2)

如何强制子类实现CreatePhysics方法,并在基本ctor中调用它?

像这样:

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

    protected Agent(...)
    {
        var physics = CreatePhysics();
        SetupPhysics(physics);
    }

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

    protected abstract IPhysics CreatePhysics();
}

public class Bicycle : Agent
{
    private double maxA;

    protected override IPhysics CreatePhysics()
    {
        ComputationOfMaxA();
        return new Physics(maxA);
    }
}

答案 2 :(得分:2)

如何使Agent的构造函数获取IPhysics对象并使其成为protected然后在Bicycle类中,您被迫调用基础上的构造函数它设置了你的类属性:

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

    protected Agent(IPhysics physicsPlugin) 
    {
        PluginPhysics = physicsPlugin;
    }
}

public class Bicycle : Agent
{
    public Bicycle(IPhysics physicsPlugin)
        : base(physicsPlugin)
    {
        Console.WriteLine("Bicycle ctor");
    }
}