对象的复制:浅复制与深复制和ICloneable接口
所谓的“对象的复制” 即生成一个与指定对象“一模一样”的“同胞兄弟”。
对于对象的复制,有浅复制与深复制两种情况。
1、 浅复制:是指当对象的字段值被复制时,字段引用的对象不会被复制。
例如,如果一个对象有一个指向字符串的字段,并且我们对该对象做了一个浅复制,那麽两个对象将引用同一个字符串。
2、 深复制:是对对象事例中字段引用的对象也进行复制的一种方式。
例如,如果一个对象有一个指向字符串的字段,并且对该对象做了一个深复制的话.我门将创建一个新的对象和一个新的字符串.新对象将指向新字符串。
3、.NET中默认的对象复制方式为浅复制,我们可以通过两种方式实现深复制。
A、类实现Icloneable接口。
B、对象序列化技术。
一、浅复制
对于只包含简单字段的对象而说,对象复制的过程可以简化为“新建一个同类型的对象,然后一个一个复制字段值”的过程。
例如以下代码:
class ClassA
{
public int AValue = 100;
}
以下方法可完成复制ClassA对象的任务:
public static ClassA CloneObject(ClassA obj)
{
ClassA newObj = new A();
newObj.AValue = obj.AValue;
return newObj;
}
以下是示例代码(假设它们与CloneObject方法位于同一个类内部):
ClassA objA = new ClassA();
ClassA other = CloneObject(objA); //将ClassA对象复制一份
上述对象复制过程很简单。但是对象之间是可以相互结合的,如果我们考虑到对象组合的情况,对象复制的问题就复杂了。以下示例代码:
public class ClassA
{
public int i=100;
public ClassB EmbedObject; //ClassA包含一个ClassB的对象
public ClassA()
{
EmbedObject = new ClassB();
}
class ClassB
{
public int BValue =200;
}
基于“通过字段值复制实现对象复制”的原则,修改如下:
static ClassA CloneObject(ClassA obj)
{
ClassA newObj = new ClassA();
newObj.AValue = obj.AValue; //字段复制
newObj.EmbedObject = obj.EmbedObject; //引用复制
return obj;
}
以下是ClassA 对象复制的示例代码:
ClassA ObjA = new ClassA();
Class other = CloneObject(objA);//将ClassA 对象复制一份
}
这时问题出现了,由于类 ClassA 中字段 EmbedObject 是一个引用类型的变量,所以仅仅将字段复制一下,带来的结果是老对象和新对象“共用”一个ClassB对象。
上述的对象复制方式称“浅复制Shallow Copy”
实际上我们是要进行“深复制Deep Copy“ 其特点是连包含的对象也一并复制。
二:深复制
浅复制是.net framework 默认的对象复制方式,object类提供了一个 Memberwise方法浅复制一个对象。
为了实现深复制,.net framework提供了一个 ICloneable 接口,要求采用“深复制”方式进行对象复制的类必须实现此接口。
public inteface ICloneable
{
object Clone();
}
下面是示例代码:
using System;
using System.Collections.Generic;
using System.Text;
namespace ObjectClone
{
class ClassA : ICloneable
{
public int AValue = 100;
public ClassB EmbedObject; //ClassA包容一个ClassB的对象
Object ICloneable.Clone()
{
ClassA ObjA = new ClassA();
ObjA.AValue = this.AValue;
ObjA.EmbedObject = (this.EmbedObject as ICloneable).Clone() as ClassB;
return ObjA;
}
}
class ClassB : ICloneable
{
public int BValue = 200;
Object ICloneable.Clone()
{
ClassB ObjB = new ClassB();
ObjB.BValue = this.BValue;
return ObjB;
}
}
class Program
{
static void Main(string[] args)
{
ClassA ObjA = new ClassA();
ObjA.EmbedObject = new ClassB();
//开始克隆
ClassA other = (ObjA as ICloneable).Clone() as ClassA;
Console.WriteLine(other.EmbedObject == ObjA.EmbedObject); //false
Console.ReadKey();
}
}
}
以上代码类A和类B都实现了 ICloneable 接口。ClassA对象的Clone方法在内部调用它所包含ClassB 对象的Clone方法完成ClassB对象的复制工作。
给对象编程实现深复制时,有几点需要注意:
1.要求所有的参与深复制的对象都实现 ICloneable 接口,或者提供其他的公有方法复制自己;
2.注意解决循环包含的问题,即类A包含类B,类B包含类C,而类C又包含类A。在这种情况下复制对象时不要形成死锁。
事实上,对象复制最简便的方法是将类标记为“[Serializable]",然后使用序列化方法复制对象。在后面的日记再做详细说明。