.NET中实现MyBaseEntity派生类的通用深拷贝方法求助
通用深拷贝方法实现方案
需求与限制
需要实现一个通用深拷贝方法,定义如下:
TTEntity CreateDeepCopy<TTEntity>(TTEntity obj) where TTEntity : MyBaseEntity
存在以下限制:
- 无法为
MyBaseEntity的任何派生类添加拷贝构造函数、自定义接口或其他需要修改新类代码的操作 - 禁止使用已废弃的
BinaryFormatter XmlSerializer因类中包含Dictionary无法正常工作,报错信息:
Cannot serialize member {...} of type System.Collections.Generic.Dictionary`2[[System.String, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Boolean, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], because it implements IDictionary.
可行解决方案
1. 使用System.Text.Json序列化反序列化
System.Text.Json原生支持Dictionary序列化,无需修改实体类,完全符合限制要求:
using System.Text.Json; TTEntity CreateDeepCopy<TTEntity>(TTEntity obj) where TTEntity : MyBaseEntity { if (obj == null) return default; var json = JsonSerializer.Serialize(obj); return JsonSerializer.Deserialize<TTEntity>(json); }
如果实体包含特殊类型(如自定义枚举、非标准可序列化类型),可通过JsonSerializerOptions添加转换器适配,基础场景直接使用即可。
2. 使用Newtonsoft.Json(Json.NET)
若项目已引入Json.NET,也可采用此方案,同样支持Dictionary:
using Newtonsoft.Json; TTEntity CreateDeepCopy<TTEntity>(TTEntity obj) where TTEntity : MyBaseEntity { if (obj == null) return default; var json = JsonConvert.SerializeObject(obj); return JsonConvert.DeserializeObject<TTEntity>(json); }
3. 反射实现手动深拷贝
如果不想依赖序列化库,可通过反射递归遍历对象成员创建副本:
using System.Reflection; TTEntity CreateDeepCopy<TTEntity>(TTEntity obj) where TTEntity : MyBaseEntity { if (obj == null) return default; // 创建目标实例 var copy = Activator.CreateInstance<TTEntity>(); // 获取所有实例字段(含公共、非公共及继承字段) var fields = typeof(TTEntity).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy); foreach (var field in fields) { var value = field.GetValue(obj); if (value == null) { field.SetValue(copy, null); continue; } var valueType = value.GetType(); // 值类型或字符串直接赋值 if (valueType.IsValueType || valueType == typeof(string)) { field.SetValue(copy, value); } // MyBaseEntity派生类递归拷贝 else if (typeof(MyBaseEntity).IsAssignableFrom(valueType)) { var nestedCopy = CreateDeepCopy((MyBaseEntity)value); field.SetValue(copy, nestedCopy); } // 处理Dictionary类型 else if (typeof(IDictionary).IsAssignableFrom(valueType)) { var newDict = Activator.CreateInstance(valueType); var dict = (IDictionary)value; foreach (DictionaryEntry entry in dict) { // 键值对分别深拷贝(值类型/字符串直接复用) var keyCopy = entry.Key.GetType().IsValueType || entry.Key is string ? entry.Key : CreateDeepCopy((MyBaseEntity)entry.Key); var valCopy = entry.Value.GetType().IsValueType || entry.Value is string ? entry.Value : CreateDeepCopy((MyBaseEntity)entry.Value); ((IDictionary)newDict).Add(keyCopy, valCopy); } field.SetValue(copy, newDict); } // 处理其他集合类型(示例以List为例,可扩展) else if (typeof(IEnumerable).IsAssignableFrom(valueType) && valueType != typeof(string)) { var itemType = valueType.GetGenericArguments()[0]; var listType = typeof(List<>).MakeGenericType(itemType); var newList = Activator.CreateInstance(listType) as IList; foreach (var item in (IEnumerable)value) { var itemCopy = item.GetType().IsValueType || item is string ? item : CreateDeepCopy((MyBaseEntity)item); newList.Add(itemCopy); } field.SetValue(copy, newList); } // 其他引用类型递归处理 else { var nestedCopy = CreateDeepCopy((MyBaseEntity)value); field.SetValue(copy, nestedCopy); } } return copy; }
注意:反射方案需自行处理循环引用、特殊集合类型等边界情况,若存在循环引用,需添加引用跟踪逻辑避免栈溢出;序列化方案可通过配置自动处理循环引用。
方案对比
- 序列化方案:实现简单,自动适配大部分类型,包括
Dictionary,代码维护成本低;性能略低于反射,但绝大多数场景可忽略。 - 反射方案:性能更优(优化后),但代码复杂度高,需手动覆盖各种类型场景,容易遗漏边界情况。
内容的提问来源于stack exchange,提问作者mariaTsu
相关产品推荐
相关产品推荐

