学习.NET (8) 实现派生类中Deep Copy的几种常用方法(通过ICloneable接口)
2008-10-03 15:15
901 查看
By Alva Chien
2008.10.03
跟C++编译器会默认提供一个Copy Constructor函数不同,C#中回避了这个问题。跟System.Object提供了一个充满歧义的Equals方法一样,System.Object还提供了一个MemberwiseClone方法,但是这个方法的名字依旧带来不小的误解,其实,这个函数只是实现了Shallow Copy,对.NET CLR中占绝大多数的Heap中使用的Reference Type,该函数只是复制了指针。
FCL提供了ICloneable接口,该接口只有一个Method:Clone(),返回值为System.Object。通过实现这个接口,该对象被认为是可以被Clone的,也就是可以被Copy的。至于是Deep Copy还是Shallow Copy就完全依赖于Clone方法是如何被实现了。
这里,遇到的第一个问题就是,当数个类之间有派生关系时,如何实现Deep Copy?
第一种方法,就是只在基类中实现ICloneable接口,并创建一个新的virtual方法,并在Clone方法中调用该virtual方法,所有的派生类只需要override这个virtual方法即可。
class Base : ICloneable
{
protected Int32 nBase = default(Int32);
public Object Clone()
{ return RealClone(null); }
protected virtual Object RealClone(Object obj)
{
if (obj == null) obj = new Base();
((Base)obj).nBase = this.nBase;
return obj;
}
}
class Derived : Base
{
protect Byte byDrv = default(Byte);
protected override Object RealClone(Object obj)
{
if (obj == null) obj = new Derived();
base.RealClone(obj);
((Derived)obj).byDrv = this.byDrv;
return obj;
}
}
第二种方法,为Base和Derived类都指定ICloneable接口。
class Base : ICloneable
{
protected Int32 nBase = default(Int32);
protected virtual Object Clone()
{
Base obj = new Base();
obj.nBase = this.nBase;
return obj;
}
}
class Derived : Base, ICloneable
{
protect Byte byDrv = default(Byte);
protected override Object Clone()
{
Derived obj = (Derived)base.Clone();
obj.byDrv = this.byDrv;
return obj;
}
}
第三种方法,采用类似C++的解决方案,为每个class实现一个Copy Constructor——即一个接受该类实例的Constructor。与第二种方法一样,同样为每个Class实现ICloneable方法。
class Base : ICloneable
{
protected Int32 nBase = default(Int32);
protected Base(Base other)
{ this.nBase = other.nBase; }
Object ICloneable.Clone()
{ return new Base(this); }
}
class Derived : Base, ICloneable
{
protect Byte byDrv = default(Byte);
protected Derived(Derived other) : base(other)
{ this.byDrv = other.byDrv; }
Object ICloneable.Clone()
{ return new Derived(this); }
}
好了,有了以上办法,可以创建支持Deep Copy的派生类了。
2008.10.03
跟C++编译器会默认提供一个Copy Constructor函数不同,C#中回避了这个问题。跟System.Object提供了一个充满歧义的Equals方法一样,System.Object还提供了一个MemberwiseClone方法,但是这个方法的名字依旧带来不小的误解,其实,这个函数只是实现了Shallow Copy,对.NET CLR中占绝大多数的Heap中使用的Reference Type,该函数只是复制了指针。
FCL提供了ICloneable接口,该接口只有一个Method:Clone(),返回值为System.Object。通过实现这个接口,该对象被认为是可以被Clone的,也就是可以被Copy的。至于是Deep Copy还是Shallow Copy就完全依赖于Clone方法是如何被实现了。
这里,遇到的第一个问题就是,当数个类之间有派生关系时,如何实现Deep Copy?
第一种方法,就是只在基类中实现ICloneable接口,并创建一个新的virtual方法,并在Clone方法中调用该virtual方法,所有的派生类只需要override这个virtual方法即可。
class Base : ICloneable
{
protected Int32 nBase = default(Int32);
public Object Clone()
{ return RealClone(null); }
protected virtual Object RealClone(Object obj)
{
if (obj == null) obj = new Base();
((Base)obj).nBase = this.nBase;
return obj;
}
}
class Derived : Base
{
protect Byte byDrv = default(Byte);
protected override Object RealClone(Object obj)
{
if (obj == null) obj = new Derived();
base.RealClone(obj);
((Derived)obj).byDrv = this.byDrv;
return obj;
}
}
第二种方法,为Base和Derived类都指定ICloneable接口。
class Base : ICloneable
{
protected Int32 nBase = default(Int32);
protected virtual Object Clone()
{
Base obj = new Base();
obj.nBase = this.nBase;
return obj;
}
}
class Derived : Base, ICloneable
{
protect Byte byDrv = default(Byte);
protected override Object Clone()
{
Derived obj = (Derived)base.Clone();
obj.byDrv = this.byDrv;
return obj;
}
}
第三种方法,采用类似C++的解决方案,为每个class实现一个Copy Constructor——即一个接受该类实例的Constructor。与第二种方法一样,同样为每个Class实现ICloneable方法。
class Base : ICloneable
{
protected Int32 nBase = default(Int32);
protected Base(Base other)
{ this.nBase = other.nBase; }
Object ICloneable.Clone()
{ return new Base(this); }
}
class Derived : Base, ICloneable
{
protect Byte byDrv = default(Byte);
protected Derived(Derived other) : base(other)
{ this.byDrv = other.byDrv; }
Object ICloneable.Clone()
{ return new Derived(this); }
}
好了,有了以上办法,可以创建支持Deep Copy的派生类了。
相关文章推荐
- .net实现文件读写的几种常用方法
- 通过实现Cloneable接口和覆盖clone()方法实现深度克隆,以及如何通过ByteArrayIOStream实现克隆
- 通过实现接口 ICloneable 复制对象
- .net学习之多线程、线程死锁、线程通信 生产者消费者模式、委托的简单使用、GDI(图形设计接口)常用的方法
- .net学习之多线程、线程死锁、线程通信 生产者消费者模式、委托的简单使用、GDI(图形设计接口)常用的方法
- Python实现发送email的几种常用方法
- 几种常用的java 实现反转的方法(reverse
- .NET中常用的几种解析JSON方法
- LaTex学习笔记(1)——LaTeX文档插入图片的几种常用方法
- [原创]java WEB学习笔记55:Struts2学习之路---详解struts2 中 Action,如何访问web 资源,解耦方式(使用 ActionContext,实现 XxxAware 接口),耦合方式(通过ServletActionContext,通过实现 ServletRequestAware, ServletContextAware 等接口的方式)
- 类继承接口, 通过接口对象new继承类的类(包含派生类),调用对象方法,其实其第一个接口继承的
- 可以通过基类实现的几种功能。vs2008 .net 2.0
- C#中接口通过基类或派生类对方法的调用
- SpringData 学习(3)—— 通过“规范”的方法实现查询
- Spring bean 通过实现 InitializingBean ,DisposableBean 接口实现初始化方法和销毁前操作
- C# 反射-通过继承接口实现创建对象并调用方法
- .net学习之继承、里氏替换原则LSP、虚方法、多态、抽象类、Equals方法、接口、装箱拆箱、字符串
- 学习jQuery必须知道的几种常用方法
- .net学习之继承、里氏替换原则LSP、虚方法、多态、抽象类、Equals方法、接口、装箱拆箱、字符串
- jQuery 学习 几种常用方法