1. 程式人生 > >c#實現深拷貝的幾種方法

c#實現深拷貝的幾種方法

代碼 序列 技術 ack [] ffffff .com ref val

  為什麽要用到深拷貝呢?比如我們建了某個類Person,並且實例化出一個對象,然後,突然需要把這個對象復制一遍,並且復制出來的對象要跟之前的一模一樣,來看下我們一般會怎麽做,看代碼

  

public class Person
{
  public string Name { get; set; }
}

class Program
{
  static void Main(string[] args)
    {
      Person sourceP = new Person() { Name = "大哥" };

      Person copyP = sourceP;
      copyP.Name = "大哥大"; // 拷貝對象改變Name值
      // 結果都是"大哥",因為實現的是淺拷貝,一個對象的改變都會影響到另一個對象
      Console.WriteLine("Person.Name: [SourceP: {0}] [CopyP:{1}]", sourceP.Name, copyP.Name);
      Console.Read();
    }
}

運行結果如圖

技術分享圖片

可以看到雖然復制了一份sourceP對象,但是修改新對象copyP的Name屬性時,居然把原來的sourceP對象的值也改了。這裏的原理是因為“=”號,在對引用類型使用時,僅僅是新建一個新的引用變量,然後把引用地址復制給了新的引用變量而已,並沒有復制真正的內容,這時候如果需要復制真正內容的話,就需要用到深拷貝的方式了。

幾種常見的深拷貝方式

1、利用反射實現

public static T DeepCopyByReflection<T>(T obj)
{
  if (obj is string || obj.GetType().IsValueType)

  return obj;

  object retval = Activator.CreateInstance(obj.GetType());
  FieldInfo[] fields = obj.GetType().GetFields(BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Static|BindingFlags.Instance);
  foreach(var field in fields)
  {
    try
    {
      field.SetValue(retval, DeepCopyByReflection(field.GetValue(obj)));
    }
    catch { }
  }

  return (T)retval;
}

2、利用二進制序列化和反序列化

public static T DeepCopyByBinary<T>(T obj)
{
  object retval;
  using (MemoryStream ms = new MemoryStream())
  {
    BinaryFormatter bf = new BinaryFormatter();
    bf.Serialize(ms, obj);
    ms.Seek(0, SeekOrigin.Begin);
    retval = bf.Deserialize(ms);
    ms.Close();
  }
  return (T)retval;
}

註意,使用二進制序列化和反序列化時,在需要序列化的類上要加上[Serializable]

[Serializable]
public class Person
{
  public string Name { get; set; }
}

3、利用xml序列化和反序列化

public static T DeepCopyByXml<T>(T obj)
{
  object retval;
  using (MemoryStream ms = new MemoryStream())
  {
    XmlSerializer xml=new XmlSerializer(typeof(T));
    xml.Serialize(ms, obj);
    ms.Seek(0, SeekOrigin.Begin);
    retval = xml.Deserialize(ms);
    ms.Close();
  }
  return (T)retval;
}

c#實現深拷貝的幾種方法