例如:我们有一个对象 A a=new A(); 在进行实际操作完这个A对象之后,它的属性发送了一些变化;我们要与于在操作完它之前的状态进行比较,这个时候我们使用复制的方式保存原来的状态,避免了重新新建一个对象一个个进行属性赋值的方式进行保存。
一. 浅度复制:
系统为我们内置提供了复制对象本身的方法,不过这个方法返回的是一个浅复制的对象副本,而且.NET给我提供了一个System.ICloneable的接口,我们通过实现这个接口,可以为对象提供自定义的克隆方法。为了搞明白浅复制和深复制,那么我先要搞懂这2者的区别。先看下面的代码:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication4 { /// <summary> /// 杯子的局部颜色属性 /// </summary> public class Colors { public string Top { get; set; } public string foot { get; set; } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication4 { /// <summary> /// 杯子的其他特征,继承ICloneable /// </summary> public class Cup:ICloneable { public int Height { get; set; } public int RL { get; set; } public Colors c { get; set; } /// <summary> /// ICloneable 成员 /// </summary> /// <returns></returns> public object Clone() { return this.MemberwiseClone(); } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication4 { /// <summary> /// 深度复制和浅度复制 /// </summary> class Program { static void Main(string[] args) { Cup cup = new Cup(); cup.Height = 20; cup.RL = 200; cup.c = new Colors() { foot = "白色", Top = "无色" }; Console.WriteLine("cup-Height:" + cup.Height);//20 Console.WriteLine("cup-RL:" + cup.RL);//200 Console.WriteLine("cup-foot:" + cup.c.foot);//白色 Cup cup1 = (Cup)cup.Clone(); cup1.RL = 100; cup1.Height = 50; cup1.c.foot = "灰色"; Console.WriteLine("cup1-Height:" + cup1.Height);//50 Console.WriteLine("cup1-RL:" + cup1.RL);//100 Console.WriteLine("cup-foot:" + cup1.c.foot); Console.WriteLine("cup-Height:" + cup.Height);//20 Console.WriteLine("cup-RL:" + cup.RL);//200 Console.WriteLine("cup-foot:" + cup.c.foot);//灰色 值发生改变了 } } }上面的代码的运行情况如下:
分析上面的代码的运行情况:
我们得出以下的结论对于值类型的成员,浅复制也是在副本中重新创建的成员,对应到内存的栈上,分配新的内存空间。那么对于引用类型则因为浅复制的时候,对象和对象副本共用同一个引用对象,那么不管是在对象还是对象副本中修改了相应的引用成员了之后,那么这个引用类型的成员就会发生变化。此处最好的例子就是cup1对象进行浅度复制后修改了颜色导致cup对象的颜色发生了变化。因为2个对象指向同一个内存地址,那么任何一个修改操作都会产生改变。使用深度复制就可以解决这一问题。
二 . 深度复制:
我们修改上诉代码中的Cup Clone()方法:
/// <summary> /// ICloneable 成员 /// </summary> /// <returns></returns> public object Clone() { Cup cup = (Cup)this.MemberwiseClone(); Colors c = new Colors(); c.Top = this.c.Top; c.foot = this.c.foot; cup.c = c; return cup; }不管是值类型的成员还是引用类型的成员,这样的对象和对象副本,对任何一个成员属性的修改,都不会影响到改变对象的值。使用这样的方式完成对象的深度复制。