Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 强制子类在计算后初始化父属性_C#_Oop - Fatal编程技术网

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
接口,只需在基类上使用一个public
Initalize()
方法,就可以完成我所展示的一切,但我喜欢在合适的时候公开框架接口。

这很好,只要物理插件不需要通过Bicycle构造函数引入的东西。。。不幸的是,这就是我的情况。鉴于此,我可能会更新这个问题。通常不赞成在构造函数中调用抽象/虚拟类。这是因为子构造函数还没有开始运行,类级变量还没有实例化,当您有多个继承级别时,这可能会变得很难管理。但是,如果将此方法与结合使用,则会出现
EndInit()
call
CreatePhysics()
一切都会好起来的。谢谢@ScottChamberlain的提示,我会看一看,并相应地更新我的答案。你在哪里执行
physicsPlugin
的计算?我可能会得出这个结论。我试图避免的是,需要进入physicsplugin构造函数的某些东西不在Bicycle类之外。虽然我很感激这不是我现在更新的问题。如果你不想要自行车类以外的零件,那么为什么不把所有东西都放在
代理的内部呢?我想我有点困惑,你到底想在这里实现什么。@DavidG maxV计算对于
自行车
类型来说是独一无二的,比如说,一辆
汽车
(它的maxV有一个不同的计算);它们都是
代理的类型。程序的主要部分(例如)将初始速度传递给
Bicycle
构造函数,但理想情况下不知道实际使用的物理插件是什么;这些信息将保存在
自行车
(一辆
汽车
可能使用不同的插件)。因此,可以在
Bicycle
中更改插件,而无需向
Bicycle
构造函数传递任何不同的内容。如果这有什么意义的话。我稍微调整了一下你的代码,让它更明显地表明,在创建物理对象之前,你需要依靠ComputationOfMaxA来完成。这比我所想的那种空检查更优雅,因为它使用了一个正确的接口,明确地初始化“相关属性”这基本上就是我这里的。当然,这感觉最像是“C#ish”。谢谢