吴佳鑫的个人专栏

当日事当日毕,没有任何借口

导航

对象的复制:浅复制与深复制和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]",然后使用序列化方法复制对象。在后面的日记再做详细说明。


posted on 2012-02-12 23:12  _eagle  阅读(674)  评论(0编辑  收藏  举报