我有一个继承自 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/