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

标签 c# oop

我有一个继承自 Agent 的子类 Bicycle。代理有一个属性,该属性取决于自行车来定义它。也就是说,智能体的物理模型需要使用速度和加速度约束进行初始化,这些约束是在每辆自行车的基础上定义的,并且对于另一种类型的智能体会有所不同。

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

每个自行车实例计算一次,但会多次使用,因此简单的静态方法无法完成这项工作。我可以在计算完它们后在父级中调用 protected 方法,但据我所知,没有办法在 child 身上强制执行此操作,或者更具体地说,在我可能不会写的任何 future child 中。

例如,我可以:

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

    ...
}

我宁愿不做任何一个,因为没有编译时方法来确保 child 初始化我能想到的 PluginPhysics,我宁愿 PluginPhysics 一旦初始化就无法更改。我也不希望在 Bicycle 类之外有需要进入 Physics 的参数部分。我明白所有这些事情可能无法同时实现。

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

最佳答案

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 接口(interface)的情况下完成我所展示的一切,只需要在基类上有一个公共(public)的 Initalize() 方法,但我喜欢在它们时公开框架接口(interface)适合。

关于c# - 强制子类在计算后初始化父属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30685376/

相关文章:

c# - 使用 JsonConverter 反序列化 JSON 字典值

c# - Binding Items控制项

c# - C++中指针和C#中引用类型的区别

c# - .Except/Yield 返回内存不足异常

c++ - 在 win32 中从工作线程到主线程的正确通信方式

java - Java语言中使用的哈希函数

c# - .Net 数据结构 : ArrayList, List、HashTable、Dictionary、SortedList、SortedDictionary——速度、内存以及何时使用它们?

javascript - 面向对象的Javascript自定义addEvent方法

c++ - 基类构造函数对派生类 C++ 不可见

python - 对某个对象进行投票最有效的方法是什么?