C#开发如何避免嵌套属性访问时的向下转型,访问者模式适用吗?
问题1:避免向下转型的可行方案
方案1:优先采用你提出的简化层级方案
这是当前场景下成本最低、可维护性最高的方案,仅需要修正你示例代码中的一处笔误:将ProductionModelA和ProductionModelB中的Parts属性从单个对象改为List<PartModelA>/List<PartModelB>即可投入使用。
该方案的核心逻辑是:A/B两条链路的嵌套关系本身就是强绑定的,不会出现ImportModelA中嵌套ProductionModelB的场景,因此不需要在基类中定义Production、Parts这类关联属性,基类仅保留全局公共属性即可。这样在ImportModelA的专属服务方法中,直接访问importModel.Production就是强类型的ProductionModelA,再访问Production.Parts就是强类型的List<PartModelA>,完全不需要任何转型操作,也没有泛型冗余的问题。后续新增C/D类模型时,只需要新增对应的三个实现类即可,维护成本极低。
方案2:优化现有泛型实现
如果你需要保留基类中对关联属性的公共访问能力,可以将泛型基类拆分为非泛型公共基类+泛型强类型基类两层,解决泛型参数传染的问题:
// 非泛型基类,放所有公共属性、公共方法,公共操作直接用这个类型,不需要带泛型 public abstract class ImportModelBase { public string ImportModelBaseProp { get; set; } public abstract ProductionModelBase GetProduction(); } // 泛型基类,仅负责强类型关联 public abstract class ImportModelBase<TProduction> : ImportModelBase where TProduction : ProductionModelBase { public TProduction Production { get; set; } public override ProductionModelBase GetProduction() => Production; } // Production层同理拆分两层 public abstract class ProductionModelBase { public string ProductionModelBaseProp { get; set; } public abstract List<PartModelBase> GetParts(); } public abstract class ProductionModelBase<TPart> : ProductionModelBase where TPart : PartModelBase { public List<TPart> Parts { get; set; } public override List<PartModelBase> GetParts() => Parts.Cast<PartModelBase>().ToList(); }
这种改造后,公共逻辑用非泛型基类处理,不需要携带泛型参数,只有需要访问特定链路特有属性的专属逻辑,才用具体类或者泛型基类,既避免了转型,也解决了泛型到处传染导致的可维护性下降问题。
问题2:访问者模式的适用性
访问者模式适用的前提是:模型层级结构稳定(很少新增A/B之外的模型类型),但外部操作种类会频繁新增(比如除了现有业务处理,后续还要加数据校验、导出、规则匹配等多种不同操作)。
如果符合上述场景,访问者模式非常适合你的需求:你可以把所有外部操作封装在不同的访问者实现类中,不需要修改模型类代码,也不需要向下转型,完全符合开闭原则。
但如果你的业务会频繁新增C/D类等新的模型链路,访问者模式反而会大幅提升维护成本:每新增一个模型类型,你需要修改所有访问者的接口,新增对应类型的访问方法,改造成本远高于前两种方案。
最终选型建议
- 优先选择简化层级方案:绝大多数业务场景下,这个方案的可读性、维护成本都是最优的,完全解决你当前的转型问题。
- 如果有大量跨链路的公共处理逻辑,再选择优化后的泛型拆分方案。
- 只有模型链路固定、操作频繁新增的场景,再考虑使用访问者模式。
内容的提问来源于stack exchange,提问作者Daftom

