C#派生类和基础构造函数参数逻辑

时间:2017-04-25 10:45:48

标签: c# oop inheritance

我有一个基类:

public class Base
{
    public Base(X x ,Y y){
        this.x = x;
        this.y = y;
    }

    public X x{get;}
    public Y y{get;}
}

和推导者:

public class Derive : Base
{
    public Derive(Z z, Q q) :Base (? ?)
    {
    }

    private void ConstructXY(Z z, Q q)
    {
        //Advanced logic for creating an X and a Y
        if(q.something == 5){
            this.x = new X(28); 
        }
        else{
            this.x = new X(25);
        }

        if(this.x.something == 25 && q == 9){
            this.y = new Y(1);
        }
        else{
            this.y = new Y(5)
        }
    }
}

现在我无法在没有“高级”逻辑的情况下正确调用基本构造函数。我曾经能够从Derive.ctor()调用ConstructXY()并从那里设置x和y,因为我删除了x和y setter,所以它不再有效。我的现实场景包含更多逻辑,所以我不愿意制造三元混乱。

5 个答案:

答案 0 :(得分:4)

如果它适合静态方法

,您可以调用“高级”逻辑

这是一种使用C#7中提供的元组的方法:

public class Base
{
    // This constructor was added to avoid calling twice ConstructXY
    public Base((X x, Y y) tuple) :
        this (tuple.x, tuple.y)
    {

    }

    public Base(X x, Y y)
    {
        this.x = x;
        this.y = y;
    }

    public X x { get; }
    public Y y { get; }
}

public class Derive : Base
{
    public Derive(Z z, Q q) : base(ConstructXY(z, q))
    {
    }

    private static (X x, Y y) ConstructXY(Z z, Q q)
    {
        X x;
        Y y;

        //Advanced logic for creating an X and a Y
        if (q.something == 5)
        {
            x = new X(5);
        }
        else
        {
            x = new X(25);
        }

        if (x.something == 25 && q == 9)
        {
            y = new Y(1);
        }
        else
        {
            y = new Y(5)
        }

        return (x, y);
    }
}

答案 1 :(得分:2)

如果你不能在基类中更改XY的访问修饰符,以便子类可以访问它们,那么你必须遵循契约,让构造函数成为唯一可能的地方你可以设置这些成员。

添加更多逻辑来计算这些值的唯一方法是使用 static 方法,例如:

public class Derive : Base
{
    public Derive(Z z, Q q)
        : base(ConstructX(q), ConstructY(q, z))
    { }

    private static X ConstructX(Q q)
    {
        if (q.something == 5)
            return new X(28);
        else
            return new X(25);
    }

    private static Y ConstructY(Q q, Z z)
    {
        if (z.something == 25 && q.something == 9)
            return new Y(1);
        else
            return new Y(5);
    }
}

由于这些是单独的方法调用,因此您无法“同时”计算这两个值,因此如果不重新计算基于{Y的结果,则无法使X的结果取决于Z的结果再次1}}和Q

另一种解决方法是通过完全删除Derive上的公共构造函数并提供静态工厂方法:

public class Derive : Base
{
    private Derive(X x, Y y)
        : base(x, y)
    { }

    public static Derive Create(Z z, Q q)
    {
        // here you can use your original logic to calculate X and Y
        X x = …
        Y y = …

        return new Derive(x, y);
    }
}

根据您的计算复杂程度,这可能是更好的解决方案。如果您确实需要原始ZQ值,只需扩展私有构造函数以获取它们并存储它们:

private Derive(Z z, Q q, X x, Y y)
    : base(x, y)
{
    this.Z = z;
    this.Q = q;
}

答案 2 :(得分:0)

为什么不将您的基类setter声明为private:

public class Base
{
    public Base(X x ,Y y){
        this.x = x;
        this.y = y;
    }

    public X x{get; private set;}
    public Y y{get; private set;}
}

那样你仍然可以在构造函数中设置它们,并且它们不能在外面设置?

答案 3 :(得分:0)

我真的不喜欢这样做,如果可能的话会避免使用它,但你可以在调用base时使用三元语句:

public Derive(Z z, Q q)
    : base(new X(xCondition ? 28 : 25), new Y(yCondition ? 1 : 5))

答案 4 :(得分:0)

使用静态方法进行转换。像这样。

public class Derive : Base
{
    public Derive(Z z, Q q) :base (ConvertToX(z, q), ConvertToY(z, q))
    {
    }

    private static X ConvertToX(Z z, Q q) {
        if(q.something == 5){
            return new X(28); 
        }
        return new X(25);
    }

    private static Y ConvertToY(Z z, Q q) {
        // TODO
    }
}