c#實現深拷貝的幾種方法
為什麽要用到深拷貝呢?比如我們建了某個類Person,並且實例化出一個對象,然後,突然需要把這個對象復制一遍,並且復制出來的對象要跟之前的一模一樣,來看下我們一般會怎麽做,看代碼
public class Person
{
public string Name { get; set; }
}
class Program
{
static void Main(string[] args)
{
Person sourceP = new Person() { Name = "大哥" };
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)
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#實現深拷貝的幾種方法