1. 程式人生 > 其它 >C#基礎_深拷貝與淺拷貝

C#基礎_深拷貝與淺拷貝

C#基礎_深拷貝與淺拷貝

概念

  • 深拷貝:二個獨立的物件,互相沒有影響。B變化,A不跟著變化,反之亦然
  • 淺拷貝:二個物件指向的引用地址是一致的,存在著影響。B變化,A也跟著變化,反之亦然
  • 其他:值型別只能進行深拷貝,引用型別可以進行深拷貝與淺拷貝。

淺拷貝現象演示:(有二個不同的物件A和B,將B深拷貝A。B變化,B也跟著變化)

物件之間賦值,就會存在淺拷貝的問題

//新建Person類
public class person
{
public int id { get; set; }
public string name { get; set; }
public int age { get; set; }
public string grade { get; set; }
}
//測試
var A = new person() { id = 1, name = "zhangsan1", age = 25, grade = "一年級" };
person B = A;
Console.WriteLine("---------------------test1:直接將A賦給B。判斷二個物件是否相等------------------------");
Console.WriteLine($"物件A-->ID:{A.id},name={A.name},age={A.age},grade={A.grade}");
Console.WriteLine($"物件B-->ID:{B.id},name={B.name},age={B.age},grade={B.grade}, A=B?{A.Equals(B)} ");

Console.WriteLine("---------------------test2:給B.ID賦值。判斷A.ID是否改變------------------------");
B.id = 2; ///test2 給B的ID賦值
Console.WriteLine($"物件A-->ID:{A.id},name={A.name},age={A.age},grade={A.grade}");
Console.WriteLine($"物件B-->ID:{B.id},name={B.name},age={B.age},grade={B.grade}, A=B?{A.Equals(B)} ");

Console.WriteLine("---------------------test3:給A.ID賦值。判斷B.ID是否改變------------------------");
A.id = 3; ///test2 給B的ID賦值
Console.WriteLine($"物件A-->ID:{A.id},name={A.name},age={A.age},grade={A.grade}");
Console.WriteLine($"物件B-->ID:{B.id},name={B.name},age={B.age},grade={B.grade}, A=B?{A.Equals(B)} ");
---------------------test1:直接將A賦給B。判斷二個物件是否相等------------------------
物件A-->ID:1,name=zhangsan1,age=25,grade=一年級
物件B-->ID:1,name=zhangsan1,age=25,grade=一年級, A=B?True
---------------------test2:給B.ID賦值。判斷A.ID是否改變------------------------
物件A-->ID:2,name=zhangsan1,age=25,grade=一年級
物件B-->ID:2,name=zhangsan1,age=25,grade=一年級, A=B?True
---------------------test3:給A.ID賦值。判斷B.ID是否改變------------------------
物件A-->ID:3,name=zhangsan1,age=25,grade=一年級
物件B-->ID:3,name=zhangsan1,age=25,grade=一年級, A=B?True

深拷貝的實現的四種方式

物件賦值,就會存在淺拷貝的問題

1. 利用反射實現

public static T DeepCopy1<T>(T obj)
{
object retval = Activator.CreateInstance(typeof(T));
PropertyInfo[] pis = typeof(T).GetProperties();
foreach (PropertyInfo pi in pis)
{
try { pi.SetValue(retval, pi.GetValue(obj, null), null); }
catch { }
}
return (T)retval;
}

2.利用xml序列化和反序列化實現

類名需要public

public static T DeepCopy2<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;
}

3.利用二進位制序列化和反序列化實現

在類前加[Serializable]

public static T DeepCopy3<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;
}

測試

///深拷貝測試
var A = new person() { id = 1, name = "zhangsan1", age = 25, grade = "一年級" };
person B = DeepCopy1(A);///深拷貝
Console.WriteLine("-------------------深拷貝test1:直接將A賦給B。判斷二個物件是否相等--------------------");
Console.WriteLine($"物件A-->ID:{A.id},name={A.name},age={A.age},grade={A.grade}");
Console.WriteLine($"物件B-->ID:{B.id},name={B.name},age={B.age},grade={B.grade}, A=B?{A.Equals(B)} ");

Console.WriteLine("-------------------深拷貝test2:給B.ID賦值。判斷A.ID是否改變------------------------");
B.id = 2; ///test2 給B的ID賦值
Console.WriteLine($"物件A-->ID:{A.id},name={A.name},age={A.age},grade={A.grade}");
Console.WriteLine($"物件B-->ID:{B.id},name={B.name},age={B.age},grade={B.grade}, A=B?{A.Equals(B)} ");

Console.WriteLine("-------------------深拷貝test2:給A.ID賦值。判斷B.ID是否改變------------------------");
A.id = 3; ///test2 給B的ID賦值
Console.WriteLine($"物件A-->ID:{A.id},name={A.name},age={A.age},grade={A.grade}");
Console.WriteLine($"物件B-->ID:{B.id},name={B.name},age={B.age},grade={B.grade}, A=B?{A.Equals(B)} ");

int source = 123;
// 值型別賦值內部執行深拷貝
int copy = source;
Console.WriteLine($"值型別-->source:{source},copy={copy},copy=source?{source.Equals(copy)} ");
copy = 567;
Console.WriteLine($"值型別-->source:{source},copy={copy},copy=source?{source.Equals(copy)} ");
---------------------深拷貝test1:直接將A賦給B。判斷二個物件是否相等------------------------
物件A-->ID:1,name=zhangsan1,age=25,grade=一年級
物件B-->ID:1,name=zhangsan1,age=25,grade=一年級, A=B?False
---------------------深拷貝test2:給B.ID賦值。判斷A.ID是否改變------------------------
物件A-->ID:1,name=zhangsan1,age=25,grade=一年級
物件B-->ID:2,name=zhangsan1,age=25,grade=一年級, A=B?False
---------------------深拷貝test2:給A.ID賦值。判斷B.ID是否改變------------------------
物件A-->ID:3,name=zhangsan1,age=25,grade=一年級
物件B-->ID:2,name=zhangsan1,age=25,grade=一年級, A=B?False
值型別-->source:123,copy=123,copy=source?True
值型別-->source:123,copy=567,copy=source?False