C#深浅拷贝
前言 等号=赋值是不是拷贝?
等号赋值相当于复制该变量存在栈上的地址,并不产生分配内存的新对象。两个变量指向同一地址,本质上是修改统一块内存,一个改变所有副本都会变。
public class Order { public int OrderNo { get; set; } public OrderItem item { set; get; } } public class OrderItem { public string SKU { set; get; } public int Price { get; set; } } //构建原始对象o_a Order o_a = new Order(); o_a.OrderNo = 20211126; OrderItem item = new OrderItem(); item.Price = 1; item.SKU = "XXX"; o_a.item = item; var o_b = o_a;//等号复制o_a存在栈上的地址 o_b.OrderNo = 20211127;//复制后修改目标对象的值类型 o_b.item.SKU = "OOO";//复制后修改目标对象的引用类型 Console.WriteLine(object.ReferenceEquals(o_b,o_a));//输出true Console.WriteLine(o_a.OrderNo+"--"+o_a.item.SKU);//输出原始 20211127--OOO 全发生改变。
一.浅拷贝(拷贝不全)
浅拷贝对于值类型,浅拷贝会分配新的内存空间将值类型直接拷贝到新对象中。
对于引用类型,浅拷贝则只会复制引用地址,指向的依然是被原始对象的同一空间。所以目标对象中的引用型字段更改,原始对象相应也会更改。
public class Order { public int OrderNo { get; set; } public OrderItem item { set; get; } //浅复制的方法 public Order QianCopy() { return (Order)MemberwiseClone(); } } public class OrderItem { public string SKU { set; get; } public int Price { get; set; } } //构建原始对象o_a Order o_a = new Order(); o_a.OrderNo = 20211126; OrderItem item = new OrderItem(); item.Price = 1; item.SKU = "XXX"; o_a.item = item; var o_b = o_a.QianCopy();//浅复制复制出一个o_b o_b.OrderNo = 20211127; o_b.item.SKU = "OOO"; Console.WriteLine(o_a.OrderNo + "--" + o_a.item.SKU); //输出原始 20211126--OOO
二.深拷贝(完全拷贝)
完全复制一个新的对象,只是引用地址不同。两个对象互相独立互不影响。深拷贝的方法有多种。
1.NewtonSoft序列化、反序列化(性能损耗大,效率低)
public class Order { public int OrderNo { get; set; } public OrderItem item { set; get; } } public class OrderItem { public string SKU { set; get; } public int Price { get; set; } } //构建原始对象o_a Order o_a = new Order(); o_a.OrderNo = 20211126; OrderItem item = new OrderItem(); item.Price = 1; item.SKU = "XXX"; o_a.item = item; Order o_b = Newtonsoft.Json.JsonConvert.DeserializeObject<Order>(Newtonsoft.Json.JsonConvert.SerializeObject(o_a)); o_b.OrderNo = 20211127; o_b.item.SKU = "OOO"; Console.WriteLine(object.ReferenceEquals(o_a, o_b));//输出false Console.WriteLine(o_a.OrderNo + "--" + o_a.item.SKU); //输出原始 20211126--XXX
2.使用反射,新建一个反射助手类。
public class ReflectionHelper { public static TOut TransRelection<TIn,TOut>(TIn tIn) { TOut tout = Activator.CreateInstance<TOut>(); var tInType = tIn.GetType(); foreach (var item in tout.GetType().GetProperties()) { var itemIn = tInType.GetProperty(item.Name); if (itemIn!=null) { item.SetValue(tout, itemIn.GetValue(tIn)); } } return tout; } }
调用,得到结果跟上个例子一致
Order o_b = ReflectionHelper.TransRelection<Order, Order>(o_a);

浙公网安备 33010602011771号