【原创+探讨】对象的深层拷贝
原文在这里:
http://blog.csdn.net/CsToD/archive/2009/07/29/4390600.aspx
遇到这么个问题,没有参考任何资料,自己想了个方法
对于自定义的一些简单类型还好,遇到.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)));
}
}
}
}
}
}
写个代码来测试一下:
class Program
{
static void Main()
{
Data3 data3 = new Data3();
Data data = new Data(data3);
data.PriValue = "Pri";