C#接口实现不同类型属性且统一存入同列表的实现方案
C# 强类型形状属性统一归集实现方案
问题根因
你当前的写法不符合C#接口实现的签名匹配规则:接口定义的dynamic类型属性,要求实现类的对应属性签名完全一致,不能直接替换为具体值类型;全程使用dynamic会丢失编译期类型校验,容易引入运行时错误。
规范实现方式
采用非泛型基接口+泛型派生接口的两层结构,既可以满足所有形状实例统一存入同个列表的需求,又能保证每个形状类的属性为强类型,不需要依赖dynamic:
- 定义非泛型
IShape作为所有形状的统一抽象,作为列表的元素类型,承载所有形状共有的方法/属性 - 定义泛型
IShape<TAttributes>继承非泛型IShape,通过泛型参数约束每个实现类的属性类型 - 具体形状类实现对应泛型接口,即可获得强类型的属性定义,同时因为继承了非泛型基接口,可以被统一归集
完整实现代码
// 非泛型基接口:所有形状的统一抽象,用于支撑同列表存储 public interface IShape { // 可在此定义所有形状共有的成员,比如CalculateArea()等通用方法 } // 泛型接口:约定形状属性的强类型 public interface IShape<TAttributes> : IShape where TAttributes : struct { TAttributes ShapeAttributes { get; set; } } // 各形状独立的属性结构体 public struct SquareAttributes { public float SizeOfSide; } public struct CircleAttributes { public float Radius; } // 具体形状实现 public class Square : IShape<SquareAttributes> { public SquareAttributes ShapeAttributes { get; set; } } public class Circle : IShape<CircleAttributes> { public CircleAttributes ShapeAttributes { get; set; } }
归集与使用
// 用非泛型接口作为列表元素类型,可统一添加所有形状实例 List<IShape> Shapes = new List<IShape>(); Shapes.Add(new Square()); Shapes.Add(new Circle()); // 遍历访问时通过模式匹配获取强类型实例,全程类型安全 foreach (var shape in Shapes) { if (shape is Square square) { float sideLength = square.ShapeAttributes.SizeOfSide; // 处理正方形逻辑 } else if (shape is Circle circle) { float radius = circle.ShapeAttributes.Radius; // 处理圆形逻辑 } }
可选扩展:非泛型层统一访问属性
如果需要在不做类型判断的场景下从IShape层面拿到属性值,可以给非泛型接口增加弱类型属性,通过显式接口实现避免暴露给强类型场景:
public interface IShape { // 仅通过非泛型接口访问时可见 object ShapeAttributes { get; } } public interface IShape<TAttributes> : IShape where TAttributes : struct { new TAttributes ShapeAttributes { get; set; } } public class Square : IShape<SquareAttributes> { public SquareAttributes ShapeAttributes { get; set; } // 显式实现非泛型接口成员,强类型访问时不会暴露该弱类型属性 object IShape.ShapeAttributes => ShapeAttributes; } public class Circle : IShape<CircleAttributes> { public CircleAttributes ShapeAttributes { get; set; } object IShape.ShapeAttributes => ShapeAttributes; }
方案优势
- 完全符合C#类型系统规范,所有强类型属性访问都有编译期校验,无
dynamic带来的运行时风险 - 各形状的属性结构体完全独立,不需要整合为大粒度统一类型,适配复杂业务场景的扩展需求
- 新增形状类型时不需要修改已有接口/基类代码,符合开闭原则
内容的提问来源于stack exchange,提问作者CrimsonFreak
相关产品推荐
相关产品推荐

