复制:对象的复制是生成一个与指定对象完全一样的新对象,实现的方式根据定义可以知道,新建一个类型相同的对象,然后复制原对象的每一个成员和字段。
浅复制:
class Program { static void Main(string[] args) { ClassA A = new ClassA(); CloneObj clone = new CloneObj(); ClassA newA= clone.CloneA(A); } } public class ClassA { public Int32 AValue = 100; } public class ClassB { public Int32 BValue = 200; } public class CloneObj { public ClassA CloneA(ClassA obj) { ClassA newAobj = new ClassA(); newAobj.AValue = obj.AValue; return newAobj; } }
上面的CloneObj的CloneA方法就是一个浅复制ClassA对象,修改代码:
class Program { static void Main(string[] args) { ClassA A = new ClassA(); CloneObj clone = new CloneObj(); ClassA newA= clone.CloneA(A); } } public class ClassA { public Int32 AValue = 100; public ClassB objB; public ClassA() { objB = new ClassB(); } } public class ClassB { public Int32 BValue = 200; } public class CloneObj { public ClassA CloneA(ClassA obj) { ClassA newAobj = new ClassA(); newAobj.AValue = obj.AValue; newAobj.objB = obj.objB; return newAobj; } }
这里ClassA里面包含了引用类型的ClassB对象,这里复制的ClassA对象,如下图:
上面这种方式就是“浅复制(Shallow Copy)”,这里可以在调试时测试下,看看A里面objB的地址和通过复制方法出来的newA的objB的地址:
地址完全一样
浅复制是.NET默认的对象复制方式,Object类提供的Memberwise方法浅复制一个对象。实现深复制,也就是上面的图中,不是共用一个ClassB对象,而是完全创建一个新的ClassB对象。这需要实现ICloneable接口.如下:
namespace ConsoleApplication2 { class Program { static void Main(string[] args) { ClassA A = new ClassA(); CloneObj clone=new CloneObj(); ClassA newA = clone.CloneA(A); } } public class ClassA:ICloneable { public Int32 AValue = 100; public ClassB objB; public ClassA() { objB = new ClassB(); } object ICloneable.Clone() { ClassA objA = new ClassA(); objA.AValue = this.AValue; objA.objB = (this.objB as ICloneable).Clone() as ClassB; return objA; } } public class ClassB:ICloneable { public Int32 BValue = 200; object ICloneable.Clone() { ClassB objB = new ClassB(); objB.BValue = this.BValue; return objB; } } public class CloneObj { public ClassA CloneA(ClassA obj) { //ClassA newAobj = new ClassA(); //newAobj.AValue = obj.AValue; //newAobj.objB = obj.objB; ClassA newAobj = (obj as ICloneable).Clone() as ClassA; return newAobj; } } }
测试结果如图:
这里完成了深复制
对象序列化
对象复制比较简单的方式是序列化,将类标记为[Serializable]。对象序列化主要解决的是对象状态的保存问题,这里所说的“对象状态”是指某一时刻对象拥有的字段值的集合。
对象的序列化:将一个内存的对象保存到流中,并在需要时从流中读取数据重建对象的过程称为“对象序列化”和“反序列化”
流:代表一连串有顺序的二进制数据。
利用序列化进行对象的复制——深复制
[Serializable] class MyClass { public int Index = 1; } class Program { static void Main(string[] args) { MyClass obj = new MyClass(); //创建一个内存流对象 using (MemoryStream ms = new MemoryStream()) { IFormatter formator = new BinaryFormatter(); formator.Serialize(ms, obj); //将对象序列化到内存流中 //克隆100个对象 for (int i = 0; i < 100; i++) { ms.Seek(0, SeekOrigin.Begin);//回到流的开头 obj = (formator.Deserialize(ms) as MyClass); //反序列化对象 obj.Index += i; //设置对象字段 Console.WriteLine("对象{0}已创建。", obj.Index); } } Console.ReadKey(); } }
原理是将对象序列化到流中,然后从流中创建对象(批量),从而实现了深复制。
读书笔记《.NET4.0面向对象编程漫谈》作者:金旭亮老师