有没有办法自动调用继承方法的所有版本?

时间:2009-12-15 23:38:32

标签: c# inheritance methods polymorphism virtual

我正在为3D建模程序编写插件。我有一个自定义类,它包装3D模型中的元素实例,然后从它包装的元素派生它的属性。当模型中的元素发生变化时,我希望我的类根据新几何更新其属性。

在下面的简化示例中。我有类AbsCurveBasd,Extrusion和Shell,它们都是相互派生的。这些类中的每一个都实现了一个RefreshFromBaseShape()方法,该方法根据类包装的当前baseShape更新特定属性。

我可以在RefreshFromBaseShape()的每个实现中调用base.RefreshFromBaseShape(),以确保更新所有属性。但我想知道是否有更好的方法,我不必记得在RefershFromBaseShape()的每个实现中都这样做?例如,因为AbsCurveBased没有无参数构造函数,所以除非构造函数调用基类构造函数,否则代码甚至不会编译。

public abstract class AbsCurveBased
{
    internal Curve baseShape;
    double Area{get;set;}

    public AbsCurveBased(Curve baseShape)
    {
        this.baseShape = baseShape;
        RefreshFromBaseShape();
    }

    public virtual void RefreshFromBaseShape()
    {
        //sets the Area property from the baseShape
    }
}


public class Extrusion : AbsCurveBased
{
    double Volume{get;set;}
    double Height{get;set;}

    public Extrusion(Curve baseShape):base(baseShape)
    {
        this.baseShape = baseShape;
        RefreshFromBaseShape();
    }

    public override void RefreshFromBaseShape()
    {
        base.RefreshFromBaseShape();
        //sets the Volume property based on the area and the height
    }
}


public class Shell : Extrusion
{
    double ShellVolume{get;set;}
    double ShellThickness{get;set;}

    public Shell(Curve baseShape): base(baseShape)
    {
        this.baseShape = baseShape;
        RefreshFromBaseShape();
    }

    public void RefreshFromBaseShape()
    {
        base.RefreshFromBaseShape();
        //sets this Shell Volume from the Extrusion properties and ShellThickness property
    }
}

2 个答案:

答案 0 :(得分:0)

你这样做的方式是一种非常典型的模式,它肯定没有任何问题 - 通常是这样的事情。没有办法强制base调用,假设它发生的时间和地点始终取决于实施者。如果您真的热衷于强制它,那么您应该考虑使用受保护的事件:

public abstract class AbsCurveBased
{
    internal Curve baseShape;
    double Area{get;set;}

    public AbsCurveBased(Curve baseShape)
    {
        this.baseShape = baseShape;
        RefreshFromBaseShape();
    }

    public void RefreshFromBaseShape()
    {
        //sets the Area property from the baseShape
        ...

        // call child handlers
        var handler = RefreshingFromBaseShape;
        if (handler != null)
            handler();
    }

    protected event Action RefreshingFromBaseShape;
}

public class Shell : Extrusion
{
    double ShellVolume{get;set;}
    double ShellThickness{get;set;}

    public Shell(Curve baseShape): base(baseShape)
    {
        this.RefreshingFromBaseShape += RefreshingFromBaseShapeHandler;

        this.baseShape = baseShape;
        RefreshFromBaseShape();
    }

    private void RefreshingFromBaseShapeHandler()
    {
        //sets this Shell Volume from the Extrusion properties and ShellThickness property
    }
}

这样,继承链中的任何类只能控制其处理程序,并且不能取消注册其祖先的处理程序,或者在祖先插入它们之前将它们插入到链中。

对于你的特定情况,这似乎太复杂了,没有价值。

此外,如果只从构造函数调用RefreshFromBaseShape,那么它可能应该是该构造函数的参数。考虑:

public abstract class AbsCurveBased
{
    internal Curve baseShape;
    double Area{get;set;}

    public AbsCurveBased(Curve baseShape)
    {
        this.baseShape = baseShape;

        //sets the Area property from the baseShape
    }

    protected AbsCurveBased(Curve baseShape, Action refreshFromBaseShape):
        this(baseShape)
    {
        refreshFromBaseShape();
    }
}

public class Shell : Extrusion
{
    double ShellVolume{get;set;}
    double ShellThickness{get;set;}

    public Shell(Curve baseShape):
        base(baseShape, RefreshFromBaseShape)
    {
    }

    protected Shell(Curve baseShape, Action refreshFromBaseShape):
        this(baseShape)
    {
        refreshFromBaseShape();
    }

    private void RefreshFromBaseShape()
    {
        //sets this Shell Volume from the Extrusion properties and ShellThickness property
    }
}

答案 1 :(得分:0)

我不确定为什么你需要一个单独的虚拟方法来做到这一点。为什么每个类都不能在自己的构造函数中进行计算?在您的示例中,Area将在AbsCurveBased构造函数中计算;音量&挤出构造函数中的高度等。

通常,从构造函数调用虚函数是不好的做法,因为虚函数在构造函数完成之前在子类中调用。所以子类中的方法正在运行,而对象只是部分通过构造。

评论后更新

在这种情况下,我会在每个类中使用私有的DoCalculate()方法。这将由构造函数调用,并且还将在构造函数中不再调用RefreshFromBaseShape()。虽然这不是减少链接基本调用的必要性,但这是一种正常的模式。