您的位置:首页 > 编程语言 > C#

一个克隆对象的C#基类

2008-04-24 11:35 351 查看
一个克隆对象的C#基类ByAmirHarel投递于2002,12,30摘要一个实现
ICloneable
接口的类。应用于:C#,.NETDownloadsourcefiles-1.27Kb

简介

虽然在现实世界中的克隆课题是有争议的,在.NET世界使用它却足够安全,难道不是吗?为实现一个类你究竟有多少次要实现ICloneable接口,而且每一次都写相同的代码,或为每个类写特定的代码。而且,当你的类加入一个新的字段时,往往会忘记更新这个新字段的克隆方法。如果我没说错的话,这种时候往往会带来恼人的bugs。这是我的类得以存在的原因。藉由反射机制的小小帮助,我建立了一个用缺省行为实现了ICloneable接口的抽象类。现在或许你正在问自己:什么是缺省行为?那么我很高兴你这样询问。克隆的缺省行为,是采用以下的规则来克隆类中的每一个字段:查看一下类中的每一个字段是否支持
ICloneable
接口如果某字段不支持
ICloneable
接口
那么该字段将以常规方式处理。这意味着,如果该字段是一个值类型,那么该值被拷贝;如果该字段是一个引用类型,克隆的字段将指向同一个对象。
如果该字段支持
ICloneable
接口
我们将使用其本身的
Clone
方法对其进行克隆。
如果该字段支持
IEnumerable
接口
我们需要检查他是否支持
IList或IDictionary接口
如果支持,那么我们迭代该集件,并且查看集合的每一项是否支持
ICloneable
接口。

如何使用

让你的类支持
Icloneable
接口所要做的就是
将你的类继承自如下所述的
BaseObject
publicclassMyClass:BaseObject
{
publicstringmyStr=”test”;
publicintid;
}
publicclassMyContainer:BaseObject
{
publicstringname=“test2”;
publicMyClass[]myArray=newMyClass[5];
publicclassMyContainer()
{
for(inti=0;i<5;i++)
{
this.myArray[I]=newMyClass();
}
}
}
现在在Main方法中加入如下代码:
staticvoidMain(string[]args)
{
MyContainercon1=newMyContainer();
MyContainercon2=(MyContainer)con1.Clone();
con2.myArray[0].id=5;
}
当监测
con2
实例时,你将会看到
MyClass
实例的第一项已经变为5,而
con1
实例却没有改变。这样你将明白加入到类中的任意
支持
ICloneable
接口的
字段将被同样地克隆。而且,如果该字段支持
IList或IDictionary接口,克隆方法将侦测该字段,轮询所有项,并同样地试图对他们进行克隆

实现

///<summary>
///BaseObject类是一个用来继承的抽象类。
///每一个由此类继承而来的类将自动支持克隆方法。
///该类实现了Icloneable接口,并且每个从该对象继承而来的对象都将同样地
///支持Icloneable接口。
///</summary>[/code]
publicabstractclassBaseObject:ICloneable
{
///<summary>
///克隆对象,并返回一个已克隆对象的引用
///</summary>
///<returns>引用新的克隆对象</returns>
publicobjectClone()[/code]
{
//首先我们建立指定类型的一个实例
[/code]objectnewObject=Activator.CreateInstance(this.GetType());
//我们取得新的类型实例的字段数组。
[/code]FieldInfo[]fields=newObject.GetType().GetFields();
inti=0;
foreach(FieldInfofiinthis.GetType().GetFields())
{
//我们判断字段是否支持ICloneable接口。
TypeICloneType=fi.FieldType.[/code]
GetInterface("ICloneable",true);
if(ICloneType!=null)
{
//取得对象的Icloneable接口。
[/code]ICloneableIClone=(ICloneable)fi.GetValue(this);
//我们使用克隆方法给字段设定新值。
fields[i].SetValue(newObject,IClone.Clone());
}
else
{
//如果该字段部支持Icloneable接口,直接设置即可。
[/code]fields[i].SetValue(newObject,fi.GetValue(this));
}
//现在我们检查该对象是否支持IEnumerable接口,如果支持,
//我们还需要枚举其所有项并检查他们是否支持IList或IDictionary接口。
TypeIEnumerableType=fi.FieldType.GetInterface
("IEnumerable",true);
if(IEnumerableType!=null)
{
//取得该字段的IEnumerable接口
IEnumerableIEnum=(IEnumerable)fi.GetValue(this);
//这个版本支持IList或IDictionary接口来迭代集合。
[/code]
TypeIListType=fields[i].FieldType.GetInterface
("IList",true);
TypeIDicType=fields[i].FieldType.GetInterface
("IDictionary",true);
intj=0;
if(IListType!=null)
{
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: