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