C#如何从含父类与子类的列表中高效创建子类对象?
优化子类实例复制方案,告别低效的类型判断
先明确场景:你有父类AnimalGroup,以及继承它的子类LionGroup、GiraffeGroup,Wild列表中存储了这些子类的实例,现在需要基于Wild生成新的Zoo列表,每个元素是原对象的副本。原实现通过逐个判断类型创建实例,不仅代码冗余,后续新增子类还要修改判断逻辑,效率和维护性都很差。下面是几种更优的实现方式:
方案1:用多态让子类自行负责复制(最推荐)
给父类定义抽象的Clone方法,每个子类自己实现复制逻辑,彻底消除类型判断:
public abstract class AnimalGroup { public string Name { get; set; } // 抽象复制方法,子类必须实现自身的复制逻辑 public abstract AnimalGroup Clone(); } public class LionGroup : AnimalGroup { public int PrideSize { get; set; } public override AnimalGroup Clone() { // 此处为浅复制,若包含引用类型成员,可自行扩展为深复制 return new LionGroup { Name = this.Name, PrideSize = this.PrideSize }; } } public class GiraffeGroup : AnimalGroup { public int NeckAverageLength { get; set; } public override AnimalGroup Clone() { return new GiraffeGroup { Name = this.Name, NeckAverageLength = this.NeckAverageLength }; } } // 生成Zoo列表只需一行代码 List<AnimalGroup> Zoo = Wild.Select(animal => animal.Clone()).ToList();
这个方案的优势:
- 完全无需类型判断,代码简洁高效
- 新增子类时只需实现
Clone方法,原有代码无需修改,符合开闭原则 - 每个子类自主控制复制逻辑,可灵活实现浅复制或深复制
方案2:用反射动态复制(适合无法修改原有类的场景)
如果不能改动父类和子类的结构,可通过反射根据对象类型动态创建实例并复制属性:
using System.Reflection; public static class AnimalCopier { public static T Clone<T>(T source) where T : AnimalGroup, new() { var target = new T(); // 复制所有公共实例属性 var props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (var prop in props) { if (prop.CanRead && prop.CanWrite) { prop.SetValue(target, prop.GetValue(source)); } } return target; } } // 生成Zoo列表 List<AnimalGroup> Zoo = Wild.Select(animal => { var cloneMethod = typeof(AnimalCopier).GetMethod("Clone").MakeGenericMethod(animal.GetType()); return (AnimalGroup)cloneMethod.Invoke(null, new object[] { animal }); }).ToList();
注意:反射性能略逊于多态,但比重复类型判断更易维护。若频繁调用,可缓存反射获取的方法以提升性能。
方案3:用类型映射字典替代重复判断
提前将类型与对应的复制逻辑存入字典,避免每次的类型判断开销:
// 提前注册各类型的复制委托 private static readonly Dictionary<Type, Func<AnimalGroup, AnimalGroup>> _cloneHandlers = new() { { typeof(LionGroup), g => new LionGroup { Name = g.Name, PrideSize = ((LionGroup)g).PrideSize } }, { typeof(GiraffeGroup), g => new GiraffeGroup { Name = g.Name, NeckAverageLength = ((GiraffeGroup)g).NeckAverageLength } } }; // 生成Zoo列表 List<AnimalGroup> Zoo = Wild.Select(g => _cloneHandlers[g.GetType()](g)).ToList();
这种方式比if-else或switch判断更高效,新增子类时只需在字典中添加一行委托即可,代码结构更清晰。
内容的提问来源于stack exchange,提问作者Alibies
相关产品推荐
相关产品推荐

