You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 08:06:28