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

如何实现A.ClassA到B.ClassB的深度拷贝(含集合等非基元类型)

问题描述

现有以下类定义:

namespace A;
public class ClassA
{
     public int A { get; set; } 
     public string B { get; set; }
     public List<typeA> TypeA { get; set; }
     public TypeB TypeB { get; set; }
}

public class typeA
{ 
    // 自定义属性
}

public class TypeB
{ 
    // 自定义属性
}

namespace B;
public class ClassB
{
     public string BB { get; set; }
     public List<A.typeA> TypeA { get; set; }
}

尝试使用以下代码将A.ClassA的数据拷贝到B.ClassB:

public class CopyClass
{
    public static void CopyObject<T>(object sourceObject, ref T destObject)
    {
        if (sourceObject == null || destObject == null)
            return;

        Type sourceType = sourceObject.GetType();
        Type targetType = destObject.GetType();

        // 遍历源对象属性
        foreach (PropertyInfo p in sourceType.GetProperties())
        {
            PropertyInfo targetObj = targetType.GetProperty(p.Name);
            // 目标无对应属性则跳过
            if (targetObj == null)
                continue;

            try
            {
                if (p.GetType() == targetObj.GetType())
                    targetObj.SetValue(destObject, p.GetValue(sourceObject, null), null);
                    // 非基元类型此处抛出异常
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Exception copying : ex.Message = {ex.Message}, inner = {ex.InnerException?.Message}");
            }
        }
    }
}

问题:拷贝非基元类型(如自定义类、集合)时会抛出异常,需要实现深度拷贝,完成ClassA与ClassB中对应属性(包括集合)的拷贝。


解决方案

要实现支持非基元类型的深度拷贝,需要修复原代码的逻辑错误,并针对不同类型的属性做差异化处理,确保每个引用类型都创建新实例而非直接赋值引用。

1. 修复原代码核心错误

原代码中p.GetType() == targetObj.GetType()的判断完全无效——它比较的是PropertyInfo自身的类型(所有属性的PropertyInfo类型都是相同的),正确的判断应该是比较属性的实际类型:p.PropertyType == targetObj.PropertyType。

2. 完整深度拷贝实现

以下实现递归处理引用类型,同时单独处理集合类型,完成深度拷贝:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;

public class DeepCopyHelper
{
    public static void DeepCopy<T>(object source, ref T destination)
    {
        if (source == null || destination == null)
            return;

        Type sourceType = source.GetType();
        Type targetType = destination.GetType();

        foreach (PropertyInfo sourceProp in sourceType.GetProperties(BindingFlags.Public | BindingFlags.Instance))
        {
            PropertyInfo targetProp = targetType.GetProperty(sourceProp.Name, BindingFlags.Public | BindingFlags.Instance);
            if (targetProp == null || !targetProp.CanWrite)
                continue;

            object sourceValue = sourceProp.GetValue(source);
            if (sourceValue == null)
            {
                targetProp.SetValue(destination, null);
                continue;
            }

            Type propType = sourceProp.PropertyType;
            // 值类型与字符串直接赋值(字符串不可变,无需深度拷贝)
            if (propType.IsValueType || propType == typeof(string))
            {
                targetProp.SetValue(destination, sourceValue);
            }
            // 处理集合类型(如List<T>)
            else if (typeof(IEnumerable).IsAssignableFrom(propType) && propType != typeof(string))
            {
                ICollection targetCollection = (ICollection)Activator.CreateInstance(targetProp.PropertyType);
                foreach (var item in (IEnumerable)sourceValue)
                {
                    object newItem = Activator.CreateInstance(item.GetType());
                    DeepCopy(item, ref newItem);
                    targetCollection.Add(newItem);
                }
                targetProp.SetValue(destination, targetCollection);
            }
            // 处理自定义引用类型
            else
            {
                object targetValue = Activator.CreateInstance(targetProp.PropertyType);
                DeepCopy(sourceValue, ref targetValue);
                targetProp.SetValue(destination, targetValue);
            }
        }
    }
}

3. 使用方式

// 初始化源对象
var sourceA = new A.ClassA
{
    A = 10,
    B = "Demo",
    TypeA = new List<A.typeA> { new A.typeA(), new A.typeA() },
    TypeB = new A.TypeB()
};

// 创建目标对象实例
var targetB = new B.ClassB();

// 执行深度拷贝
DeepCopyHelper.DeepCopy(sourceA, ref targetB);

注意事项

  • 要求所有自定义引用类型必须具备无参构造函数,如果需要支持有参构造,可以扩展代码添加构造函数参数匹配逻辑
  • 如果存在循环引用(比如对象A引用对象B,对象B又引用对象A),需要额外添加缓存字典(如Dictionary<object, object>)记录已拷贝的对象,避免无限递归
  • 该实现仅处理公共实例属性,如需处理私有属性或字段,可调整BindingFlags参数

内容的提问来源于stack exchange,提问作者Nodoid

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 23:45:44