C#动态数据继承优化:如何避免子类重复实现Data属性?
解决方案推荐
1. 抽象基类+泛型中间类(兼顾统一访问与DRY原则)
这是最平衡的方案,既支持List<A>统一处理所有子类,又避免了每个子类重复实现Data属性的代码。
实现代码
// 基础抽象类,保留所有公共属性 public abstract class A { public int Id { get; set; } public string Name { get; set; } // 定义统一访问的抽象属性 public abstract object DataAsObject { get; set; } } // 泛型中间类,封装强类型Data的实现逻辑 public abstract class A<T> : A { public T Data { get; set; } // 自动映射到基类的抽象属性,无需子类重复编写 public override object DataAsObject { get => Data; set => Data = (T)value; } } // 实际子类只需指定Data类型,无冗余代码 public class B : A<DataForB> { } public class C : A<DataForC> { }
优势
- 完全符合DRY原则:重复逻辑只在泛型中间类
A<T>中实现一次 - 支持统一处理:
List<A>可以存储所有子类实例,通过DataAsObject访问数据 - 保留类型安全:如果知道具体子类类型,可强转为
A<DataForB>直接使用强类型的Data属性
2. 基类封装反射逻辑(子类零修改)
如果不想改动现有子类结构,可以把反射逻辑封装在基类中,通过缓存优化性能,同时提供统一的访问入口。
实现代码
public class A { public int Id { get; set; } public string Name { get; set; } // 缓存每个类型的Data属性,避免重复反射 private static readonly Dictionary<Type, PropertyInfo> _dataPropCache = new(); // 统一访问的动态属性 public dynamic Data { get { var type = GetType(); if (!_dataPropCache.TryGetValue(type, out var prop)) { prop = type.GetProperty("Data") ?? throw new InvalidOperationException("子类未定义Data属性"); _dataPropCache[type] = prop; } return prop.GetValue(this); } set { var type = GetType(); if (!_dataPropCache.TryGetValue(type, out var prop)) { prop = type.GetProperty("Data") ?? throw new InvalidOperationException("子类未定义Data属性"); _dataPropCache[type] = prop; } prop.SetValue(this, value); } } } // 子类保持原有定义不变 public class B : A { public DataForB Data { get; set; } }
优势
- 子类无需任何修改,直接复用现有代码
- 反射逻辑仅封装一次,性能优于手动重复反射(缓存避免重复查找属性)
- 调用简单:直接通过
a.Data访问,动态类型自动适配子类的Data类型
3. 访问者模式(适合差异化Data处理场景)
如果你的核心需求是对不同类型的Data执行差异化逻辑,而非单纯的统一访问,访问者模式可以避免大量is/as类型判断,让代码更优雅。
实现代码
// 定义访问者接口,对应每种Data类型的处理方法 public interface IDataVisitor { void Visit(DataForB data); void Visit(DataForC data); // 扩展其他Data类型的Visit方法 } // 基类定义接受访问者的抽象方法 public abstract class A { public int Id { get; set; } public string Name { get; set; } public abstract void Accept(IDataVisitor visitor); } // 子类实现Accept方法,传递自身的Data给访问者 public class B : A { public DataForB Data { get; set; } public override void Accept(IDataVisitor visitor) { visitor.Visit(Data); } } public class C : A { public DataForC Data { get; set; } public override void Accept(IDataVisitor visitor) { visitor.Visit(Data); } } // 具体访问者实现不同Data的处理逻辑 public class DataProcessor : IDataVisitor { public void Visit(DataForB data) { // 处理DataForB的业务逻辑 } public void Visit(DataForC data) { // 处理DataForC的业务逻辑 } }
使用方式
List<A> items = new List<A> { new B(), new C() }; var processor = new DataProcessor(); foreach (var item in items) { item.Accept(processor); }
优势
- 避免类型判断:无需在业务逻辑中写
if (item is B b) { ... } - 符合开闭原则:新增Data类型只需扩展访问者接口和子类,不修改现有逻辑
内容的提问来源于stack exchange,提问作者Gwydion
相关产品推荐
相关产品推荐

