在派生中指定字段类型 class

Specify field type in derived class

出于向后兼容的原因,我有一个 Rectangle2d 和一个派生自它的 Rectangle3d。这样做时,class'“转换”字段的类型应从 Transform2d 更改为 Transform3d,它是 Transform2d 的派生版本。 这是一个简化的例子:

class Transform2
{
    protected float positionX;
    protected float positionY;
}

class Transform3 : Transform2
{
    protected float positionZ;
}


class Rectangle2d
{
    protected Transform2 transform;
}

class Rectangle3d : Rectangle2d
{
    // Does not work: Just hides Rectangle2d.transform
    protected new Transform3 transform;
}

我不喜欢的一个解决方案是不使用转换 class 而是直接字段:

class Rectangle2d
{
    protected float positionX;
    protected float positionY;
}

class Rectangle3d : Rectangle2d
{
    protected float positionZ;
}

在我看来,当第二种方法有效并且第一种方法只是第二种方法有一些束缚时,应该有一个干净的解决方案。至少它希望如此。

版本:.NET Framework 4.6.1

继承意味着 is-a 关系。 Rectangle3d 不是 2d,所以它可能不应该继承自 Rectangle2d

也就是说,如果你必须这样做,我建议你使用泛型

public abstract class Transform<T>
{
    protected T transform;
}

public class Rectangle2d : Transform<Transform2> {}
public class Rectangle3d : Transform<Transform3> {}

在此模型中,2d 和 3d 都有一个 属性 transform,它是强类型的。

你要求的是不可能的,字段不能被覆盖。这是设计指南不鼓励公开可见(并且 protected 是公开可见的)字段的部分原因。您可以将其抽象为 属性,不过:

class Rectangle2d
{
    private Transform2d transform;

    protected virtual Transform2d Transform => transform;
} 

class Rectangle3d
{
    private Transform3d transform;

    protected override Transform2d Transform => transform;
} 

理想情况下,您的基础 class 应该尽可能少地依赖具体的 transform 字段,而是使用 Transform 属性。然而,作为一个设计建议,考虑将常见行为抽象为 abstract RectangleBase 并让 2D 和 3D 变体继承它,而不是相互继承。您正像现在一样从 Rectangle2d 中创建一个相当脆弱的基础 class。