【原创+探讨】对象的深层拷贝
原文在这里:
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";