如何无需泛型继承类,约束子类的继承属性为基类型子类型
无需泛型实现子类属性强类型化的方案
我明白你不想用泛型类的原因——确实有时候会觉得这种写法有点“重”。针对你的需求,不用泛型也能让SpecificShape中的texture属性被识别为SpecificTexture类型,下面给你两种简便的实现方式:
方案1:用new关键字隐藏基类属性
在子类中定义一个同名的texture属性,用new关键字覆盖基类的属性,指定为SpecificTexture类型,同时包装基类的属性来完成取值和赋值:
public class Shape { public Texture texture { get; set; } } public class Texture { } public class SpecificTexture : Texture { } public class SpecificShape : Shape { // 用new关键字隐藏基类的texture属性,指定为SpecificTexture类型 public new SpecificTexture texture { get => base.texture as SpecificTexture ?? throw new InvalidOperationException("当前Texture不是SpecificTexture类型"); set => base.texture = value; } public SpecificShape() { texture = new SpecificTexture(); } }
优势:
- 完全贴合你的需求:在
SpecificShape内部访问texture时,编译器会直接将其识别为SpecificTexture类型,不用每次手动强制转换 - 实现简单,甚至不需要修改基类的代码(如果基类是你无法改动的第三方类,这个方案特别实用)
需要注意的点:
- 当你把
SpecificShape实例向上转型为Shape时,访问的还是基类的Texture类型属性——这是继承的固有特性,没办法避免 - 建议在getter里加类型检查(比如上面的
as转换+异常抛出),防止后续如果基类的texture被意外赋值为其他Texture子类时,出现类型转换异常
方案2:新增专属强类型属性(不隐藏基类属性)
如果你不想和基类属性重名,可以新增一个专门的强类型属性,比如SpecificTextureProp,同时关联基类的texture属性:
public class SpecificShape : Shape { public SpecificTexture SpecificTextureProp { get => base.texture as SpecificTexture ?? throw new InvalidOperationException("当前Texture不是SpecificTexture类型"); set => base.texture = value; } public SpecificShape() { SpecificTextureProp = new SpecificTexture(); } }
优势:
- 不会和基类的
texture属性产生命名冲突,代码可读性更高 - 同样能在子类中直接使用强类型的属性,不用强制转换
小缺点:
- 得用新的属性名,不能直接复用
texture这个名称
题外话:为什么泛型是更规范的选择?
虽然上面的方案能满足你的需求,但你提到的泛型方案(Shape2<T>)其实是类型安全性更高的写法——它在编译期就约束了texture的类型,从根源上避免了运行时的类型检查和转换异常。如果后续你需要给多个不同的Texture子类配对对应的Shape子类,泛型的扩展性会好很多。不过如果你的场景只需要处理这一对子类,上面的简便方案完全够用。
内容的提问来源于stack exchange,提问作者Quidam
相关产品推荐
相关产品推荐

