C#中实现对象的深拷贝(Deep Copy)
作者:作者不详  发布日期:2011/06/12 18:41:22
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)));
               }
            }
         }
      }
   }
}




写个代码来测试一下:

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;
}



来自CSDN博客:http://blog.csdn.net/CsToD/archive/2009/07/29/4390600.aspx



本文来源:
上一篇 下一篇