您的位置:首页 > 电脑网络 > 笔记本 > 非用ICloneable不可的理由

非用ICloneable不可的理由

luyued 发布于 2011-02-03 06:36   浏览 N 次  

好吧,我承认,这是一个反标题,实际的情况是:我找不到一个非用ICloneable不可的理由。事实上,接口ICloneable还会带来误解,因为它只有一个Clone方法。

我们都知道,对象的拷贝分为:浅拷贝和深拷贝。ICloneable仅有一个Clone方法使我们无法从命名的角度去区分到底是哪个拷贝。

浅拷贝:将对象的字段复制到副本(新的对象)中,同时将字段的值也赋值过去,但是引用类型字段只复制引用,而不是引用类型本身。这意味着,源对象引用类型字段的值改变了,会影响到副本中对应的值也改变;

深拷贝:将对象的字段复制到副本(新的对象)中,无论是值类型还是引用类型字段,都会复制类型本身及类型的值。这意味着,源对象引用类型字段的值改变了,不会影响到副本中对应的值;

于是问题来了,如果类型继承了ICloneable接口,那么类型中的Clone是浅拷贝还是深拷贝。微软的解释是:你既可以在Clone方法中实现浅拷贝,也可以实现深拷贝。那么,为什么不直接提供两个方法呢?比如:DeepClone或者ShallowClone。还是,一般类型的创建,只要实现了浅拷贝就不需要再实现深拷贝(或者反之),所以我们没有必要提供两个方法。

下面是一个既实现了浅拷贝也实现深拷贝的例子:

代码
[Serializable]
class Employee : ICloneable
{
public string IDCode { get; set; }
public int Age { get; set; }
public Department Department { get; set; }

#region ICloneable 成员

public object Clone()
{
return this.MemberwiseClone();
}

#endregion

public Employee DeepClone()
{
using (Stream objectStream = new MemoryStream())
{
IFormatter formatter = new BinaryFormatter();
formatter.Serialize(objectStream, this);
objectStream.Seek(0, SeekOrigin.Begin);
return formatter.Deserialize(objectStream) as Employee;
}
}

public Employee ShallowClone()
{
return Clone() as Employee;
}
}

实际上,ICloneable还带来一个问题(该问题Bill Wagner在Effcitive c#中曾经论述过),那就是:如果类型继承自ICloneable,但是同时它不是一个Sealed类型的话,它们的子类的默认Clone方法会带来BUG(子类的Clone方法会返回父类的副本,而不是子类本身)。这会逼迫所有的子类都重写Clone方法;

ICloneable的Clone方法的另一个问题是:它不是类型安全的,它返回的是Object,使用它的时候还设计到转型的问题,而我们自己实现的Clone方法却可以规避掉这个问题(如上文代码)。

综上所述,类型确实没必要继承ICloneable接口,如果类型本身需要实现拷贝功能,直接公开方法就行。如果在应用中你觉得确实必须实现这个接口的,来指正我吧。

作者: 陆敏技 发表于 2011-02-02 10:35 原文链接

评论: 4 查看评论发表评论

最新新闻:
· 作为一个程序员,数学对你到底有多重要(2011-02-02 10:31)
· 谷歌推出SpeaktoTweet服务 打电话发微博(2011-02-02 08:59)
· 社交新闻网站Digg整站改版欲挽回用户(2011-02-02 08:59)
· 苹果APP被指缺少人性化:点击就付费没纠错机会(2011-02-02 08:06)
· 马云拟解决物流业四难题(2011-02-02 08:05)

编辑推荐:jQuery 1.5 正式版发布

网站导航:博客园首页 我的园子 新闻 闪存 小组 博问 知识库

广告赞助商