C# 强制子类在计算后初始化父属性
我有一个子类C# 强制子类在计算后初始化父属性,c#,oop,C#,Oop,我有一个子类Bicycle,它继承自Agent。代理具有一个属性,该属性依赖于自行车来定义它。也就是说,需要使用速度和加速度约束对代理的物理模型进行初始化,这些约束是在每辆自行车的基础上定义的,并且对于另一种类型的代理是不同的 我遇到的问题是,我无法在base()构造函数中传递需要计算的参数(速度/加速度需要计算才能从理论分布中得出),因为当然子类尚未实例化 每个自行车实例都会进行一次计算,但会使用多次,因此简单的静态方法无法完成这项工作。我可以在计算完后在父对象中调用protected方法,但
Bicycle
,它继承自Agent
。代理具有一个属性,该属性依赖于自行车来定义它。也就是说,需要使用速度和加速度约束对代理的物理模型进行初始化,这些约束是在每辆自行车的基础上定义的,并且对于另一种类型的代理是不同的
我遇到的问题是,我无法在base()
构造函数中传递需要计算的参数(速度/加速度需要计算才能从理论分布中得出),因为当然子类尚未实例化
每个自行车实例都会进行一次计算,但会使用多次,因此简单的静态方法无法完成这项工作。我可以在计算完后在父对象中调用protected
方法,但是在子对象中,或者更具体地说,在我可能不会编写的任何未来子对象中,没有办法强制执行该方法
例如,我可以:
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
一旦初始化就不能更改。我也不希望在Bicycle
类之外有需要进入物理
的部分参数。我明白,所有这些事情不可能同时发生
在调用任何相关的类对象之前,父类中缺少措辞强硬的文档或大量运行时空检查,如果不能在构造函数中初始化父类字段,我是否缺少一种明显的C#ish方式来强制子类在使用前初始化父类字段?如何强制子类实现
CreatePhysics
方法,并在基构造函数中调用它
像这样:
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);
}
}
让
代理的构造函数
获取IPhysics
对象并使其受保护
怎么样,然后在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");
}
}
非常接近,但是您不应该尝试从构造函数调用虚拟方法。但是,如果您结合使用延迟加载技巧,并且可以将插件的创建推迟到构造函数完成之后
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
对象,但是如果他们忘记调用initialize函数,物理对象上的getter将在第一次使用时触发initialize调用本身
你可以不使用
ISupportInitialize
接口,只需在基类上使用一个publicInitalize()
方法,就可以完成我所展示的一切,但我喜欢在合适的时候公开框架接口。这很好,只要物理插件不需要通过Bicycle构造函数引入的东西。。。不幸的是,这就是我的情况。鉴于此,我可能会更新这个问题。通常不赞成在构造函数中调用抽象/虚拟类。这是因为子构造函数还没有开始运行,类级变量还没有实例化,当您有多个继承级别时,这可能会变得很难管理。但是,如果将此方法与结合使用,则会出现EndInit()
callCreatePhysics()
一切都会好起来的。谢谢@ScottChamberlain的提示,我会看一看,并相应地更新我的答案。你在哪里执行physicsPlugin
的计算?我可能会得出这个结论。我试图避免的是,需要进入physicsplugin构造函数的某些东西不在Bicycle类之外。虽然我很感激这不是我现在更新的问题。如果你不想要自行车类以外的零件,那么为什么不把所有东西都放在代理的内部呢?我想我有点困惑,你到底想在这里实现什么。@DavidG maxV计算对于自行车
类型来说是独一无二的,比如说,一辆汽车
(它的maxV有一个不同的计算);它们都是代理的类型。程序的主要部分(例如)将初始速度传递给Bicycle
构造函数,但理想情况下不知道实际使用的物理插件是什么;这些信息将保存在自行车
(一辆汽车
可能使用不同的插件)。因此,可以在Bicycle
中更改插件,而无需向Bicycle
构造函数传递任何不同的内容。如果这有什么意义的话。我稍微调整了一下你的代码,让它更明显地表明,在创建物理对象之前,你需要依靠ComputationOfMaxA来完成。这比我所想的那种空检查更优雅,因为它使用了一个正确的接口,明确地初始化“相关属性”这基本上就是我这里的。当然,这感觉最像是“C#ish”。谢谢