C#中实现对象的深拷贝(Deep Copy)
关于C#中实现对象的深拷贝的问题,没有参考任何资料,自己想了个方法对于自定义的一些简单类型还好,遇到.Net里一些复杂的类就无能为力了,不知道还有什么更好的方法。
下面的代码演示对象深拷贝
class CsToD
{
//基本思想是:一个对象所占据的内存空间,取决于它的实例字段(包括继承树上的私有实例字段)
public T DeepCloneObject<T>(T obj) where T : class
{
//System.String类型似乎比较特殊,复制它的所有字段,并不能复制它本身
//不过由于System.String的不可变性,即使指向同一对象,也无所谓
//而且.NET里本来就用字符串池来维持
if (obj == null || obj.GetType() == typeof(string))
return obj;
object newObj = null;
try
{
//尝试调用默认构造函数
newObj = Activator.CreateInstance(obj.GetType());
}
catch
{
//失败的话,只好枚举构造函数了
foreach (ConstructorInfo ci in obj.GetType().GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
{
try
{
ParameterInfo[] pis = ci.GetParameters();
object[] objs = new object[pis.Length];
for (int i = 0; i < pis.Length; i++)
{
if (pis[i].ParameterType.IsValueType)
objs[i] = Activator.CreateInstance(pis[i].ParameterType);
else
//参数类型可能是抽象类或接口,难以实例化
//我能想到的就是枚举应用程序域里的程序集,找到实现了该抽象类或接口的类
//但显然过于复杂了
objs[i] = null;
}
newObj = ci.Invoke(objs);
//无论调用哪个构造函数,只要成功就行了
break;
}
catch
{
}
}
}
foreach (FieldInfo fi in obj.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
{
if (fi.FieldType.IsValueType || fi.FieldType == typeof(string))
fi.SetValue(newObj, fi.GetValue(obj));
else
fi.SetValue(newObj, DeepCloneObject(fi.GetValue(obj)));
}
//基类的私有实例字段在子类里检索不到,但它仍占据子类对象的内存空间
Deep(newObj, obj);
return (T)newObj;
}
//克隆继承树上的私有实例字段
public void Deep(object newObj, object obj)
{
for (Type father = newObj.GetType().BaseType; father != typeof(object); father = father.BaseType)
{
foreach (FieldInfo fi in father.GetFields(BindingFlags.NonPublic | BindingFlags.Instance))
{
//只需要处理私有字段,因为非私有成员已经在子类处理过了
if (fi.IsPrivate)
{
if (fi.FieldType.IsValueType || fi.FieldType == typeof(string))
{
fi.SetValue(newObj, fi.GetValue(obj));
}
else
{
fi.SetValue(newObj, DeepCloneObject(fi.GetValue(obj)));
}
}
}
}
}
}
{
//基本思想是:一个对象所占据的内存空间,取决于它的实例字段(包括继承树上的私有实例字段)
public T DeepCloneObject<T>(T obj) where T : class
{
//System.String类型似乎比较特殊,复制它的所有字段,并不能复制它本身
//不过由于System.String的不可变性,即使指向同一对象,也无所谓
//而且.NET里本来就用字符串池来维持
if (obj == null || obj.GetType() == typeof(string))
return obj;
object newObj = null;
try
{
//尝试调用默认构造函数
newObj = Activator.CreateInstance(obj.GetType());
}
catch
{
//失败的话,只好枚举构造函数了
foreach (ConstructorInfo ci in obj.GetType().GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
{
try
{
ParameterInfo[] pis = ci.GetParameters();
object[] objs = new object[pis.Length];
for (int i = 0; i < pis.Length; i++)
{
if (pis[i].ParameterType.IsValueType)
objs[i] = Activator.CreateInstance(pis[i].ParameterType);
else
//参数类型可能是抽象类或接口,难以实例化
//我能想到的就是枚举应用程序域里的程序集,找到实现了该抽象类或接口的类
//但显然过于复杂了
objs[i] = null;
}
newObj = ci.Invoke(objs);
//无论调用哪个构造函数,只要成功就行了
break;
}
catch
{
}
}
}
foreach (FieldInfo fi in obj.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
{
if (fi.FieldType.IsValueType || fi.FieldType == typeof(string))
fi.SetValue(newObj, fi.GetValue(obj));
else
fi.SetValue(newObj, DeepCloneObject(fi.GetValue(obj)));
}
//基类的私有实例字段在子类里检索不到,但它仍占据子类对象的内存空间
Deep(newObj, obj);
return (T)newObj;
}
//克隆继承树上的私有实例字段
public void Deep(object newObj, object obj)
{
for (Type father = newObj.GetType().BaseType; father != typeof(object); father = father.BaseType)
{
foreach (FieldInfo fi in father.GetFields(BindingFlags.NonPublic | BindingFlags.Instance))
{
//只需要处理私有字段,因为非私有成员已经在子类处理过了
if (fi.IsPrivate)
{
if (fi.FieldType.IsValueType || fi.FieldType == typeof(string))
{
fi.SetValue(newObj, fi.GetValue(obj));
}
else
{
fi.SetValue(newObj, DeepCloneObject(fi.GetValue(obj)));
}
}
}
}
}
}
写个代码来测试一下:
class Program
{
static void Main()
{
Data3 data3 = new Data3();
Data data = new Data(data3);
data.PriValue = "Pri";
data.Integer = 3;
//修改cloneData对象,并未影响到data对象,说明克隆成功
CsToD ctd = new CsToD();
Data cloneData = ctd.DeepCloneObject(data);
cloneData.Integer = 1000;
cloneData.PriValue = "clone";
cloneData.Value.D3String = "clonestr";
Console.WriteLine(data.Integer + "<->" + cloneData.Integer);
Console.WriteLine(data.PriValue + "<->" + cloneData.PriValue);
Console.WriteLine(data.Value.D3String + "<->" + cloneData.Value.D3String);
//而如果修改refData对象,data对象也被改变,说明是同一对象
Data refData = data;
refData.Integer = 555;
refData.PriValue = "ref";
refData.Value.D3String = "refstr";
Console.WriteLine(data.Integer + "<->" + refData.Integer);
Console.WriteLine(data.PriValue + "<->" + refData.PriValue);
Console.WriteLine(data.Value.D3String + "<->" + refData.Value.D3String);
}
}
class Data:Data2
{
public Data(Data3 value)
{
this.Value = value;
}
public Data() { }
public Data3 Value;
}
class Data2
{
public Data2(int value)
{
this.Integer = value;
}
public string PriValue
{
get
{
return priValue;
}
set
{
priValue = value;
}
}
public Data2() { }
public int Integer;
private string priValue;
}
class Data3
{
public Data3()
{
D3String = "D3";
d3Integer = 3;
}
public string D3String;
private int d3Integer;
}
{
static void Main()
{
Data3 data3 = new Data3();
Data data = new Data(data3);
data.PriValue = "Pri";
data.Integer = 3;
//修改cloneData对象,并未影响到data对象,说明克隆成功
CsToD ctd = new CsToD();
Data cloneData = ctd.DeepCloneObject(data);
cloneData.Integer = 1000;
cloneData.PriValue = "clone";
cloneData.Value.D3String = "clonestr";
Console.WriteLine(data.Integer + "<->" + cloneData.Integer);
Console.WriteLine(data.PriValue + "<->" + cloneData.PriValue);
Console.WriteLine(data.Value.D3String + "<->" + cloneData.Value.D3String);
//而如果修改refData对象,data对象也被改变,说明是同一对象
Data refData = data;
refData.Integer = 555;
refData.PriValue = "ref";
refData.Value.D3String = "refstr";
Console.WriteLine(data.Integer + "<->" + refData.Integer);
Console.WriteLine(data.PriValue + "<->" + refData.PriValue);
Console.WriteLine(data.Value.D3String + "<->" + refData.Value.D3String);
}
}
class Data:Data2
{
public Data(Data3 value)
{
this.Value = value;
}
public Data() { }
public Data3 Value;
}
class Data2
{
public Data2(int value)
{
this.Integer = value;
}
public string PriValue
{
get
{
return priValue;
}
set
{
priValue = value;
}
}
public Data2() { }
public int Integer;
private string priValue;
}
class Data3
{
public Data3()
{
D3String = "D3";
d3Integer = 3;
}
public string D3String;
private int d3Integer;
}
来自CSDN博客:http://blog.csdn.net/CsToD/archive/2009/07/29/4390600.aspx
参考文档:
使用DeepSeek生成DevExpress表格、窗体、C#模型代码并集成到开发框架|C/S开发框架
达梦数据库使用DmBulkCopy批导数据解决方案|C/S开发框架
Oracle:EFCore使用OracleBulkCopy实现批量导入数据|C/S开发框架
SqlBulkCopy.WriteToServer报错:“Unable to cast object of type 'System.Guid' to type 'System.String'.”
C#使用SqlBulkCopy快速导入Excel文件(xls/xlsx)-C/S开发框架
C# SqlBulkCopy通用数据同步程序|跨数据库导入数据
C# 实现对象浅拷贝Copy(极速复制对象)
BUG: dalUser.CopyPermission方法
CSFrameworkV6旗舰版 | 多语言及国际化|C/S开发框架
达梦数据库.NETCore.NET8实践指南|C/S软件开发框架|C/S开发框架
DevExpress GridControl显示主从表数据(Master/Detail)|C/S开发框架
DevExpress XtraReport 开发指南|单表报表设计详解(C#)|C/S开发框架
CSFrameworkV6旗舰版 | 导入导出Excel文件数据开发教程|C/S开发框架
.NET代码生成器V6.1 - 快速生成Winform窗体代码
CSFrameworkV6旗舰版 | 单表基础资料窗体完整C#源码|C/S开发框架
CSFrameworkV6旗舰版 | 业务单据复制功能,支持复制多级明细表|C/S开发框架
使用DeepSeek生成DevExpress表格、窗体、C#模型代码并集成到开发框架|C/S开发框架
达梦数据库使用DmBulkCopy批导数据解决方案|C/S开发框架
Oracle:EFCore使用OracleBulkCopy实现批量导入数据|C/S开发框架
SqlBulkCopy.WriteToServer报错:“Unable to cast object of type 'System.Guid' to type 'System.String'.”
C#使用SqlBulkCopy快速导入Excel文件(xls/xlsx)-C/S开发框架
C# SqlBulkCopy通用数据同步程序|跨数据库导入数据
C# 实现对象浅拷贝Copy(极速复制对象)
BUG: dalUser.CopyPermission方法
CSFrameworkV6旗舰版 | 多语言及国际化|C/S开发框架
达梦数据库.NETCore.NET8实践指南|C/S软件开发框架|C/S开发框架
DevExpress GridControl显示主从表数据(Master/Detail)|C/S开发框架
DevExpress XtraReport 开发指南|单表报表设计详解(C#)|C/S开发框架
CSFrameworkV6旗舰版 | 导入导出Excel文件数据开发教程|C/S开发框架
.NET代码生成器V6.1 - 快速生成Winform窗体代码
CSFrameworkV6旗舰版 | 单表基础资料窗体完整C#源码|C/S开发框架
CSFrameworkV6旗舰版 | 业务单据复制功能,支持复制多级明细表|C/S开发框架
其它资料:
什么是C/S结构? | C/S框架核心组成部分 | C/S框架-WebService部署图 | C/S框架-权限管理 | C/S结构系统框架 - 5.1旗舰版介绍 | C/S结构系统框架 - 功能介绍 | C/S结构系统框架 - 产品列表 | C/S结构系统框架 - 应用展示(图) | 三层体系架构详解 | C/S架构轻量级快速开发框架 | C/S框架网客户案例 | WebApi快速开发框架 | C/S框架代码生成器 | 用户授权注册软件系统 | 版本自动升级软件 | 数据库底层应用框架 | CSFramework.CMS内容管理系统 |
什么是C/S结构? | C/S框架核心组成部分 | C/S框架-WebService部署图 | C/S框架-权限管理 | C/S结构系统框架 - 5.1旗舰版介绍 | C/S结构系统框架 - 功能介绍 | C/S结构系统框架 - 产品列表 | C/S结构系统框架 - 应用展示(图) | 三层体系架构详解 | C/S架构轻量级快速开发框架 | C/S框架网客户案例 | WebApi快速开发框架 | C/S框架代码生成器 | 用户授权注册软件系统 | 版本自动升级软件 | 数据库底层应用框架 | CSFramework.CMS内容管理系统 |
在线客服
