2010-07-17 51 views

回答

5

Pavel Minaev's answer from another discussion:

其他人已经解释有关MemberwiseClone,但没有人给它为什么被保护的解释。我会尽力说明理由。

这里的问题是MemberwiseClone只是盲目地复制状态。在许多情况下,这是不可取的。例如,该对象可能有一个专用字段,它是对List的引用。一个浅的副本,比如MemberwiseClone会做什么,会导致新的对象指向同一个列表 - 而这个类可能会被写入,不会期望该列表与其他人共享。

或者一个对象可以有某种形式的ID字段,在构造函数中生成 - 再一次,当您克隆它时,会得到两个具有相同ID的对象,这可能会导致方法中出现各种奇怪的失败,独特。

或者说您有一个打开套接字或文件流的对象,并存储对该对象的引用。 MemberwiseClone只会复制引用 - 你可以想象,两个对象试图将调用交叉到同一个流不会结束。

简而言之,对于任意对象,“克隆”不是一个明确定义的操作。成员运算符=在C++中默认为所有类提供的事实更令人讨厌,因为人们经常忘记它在那里,并且对于复制没有意义的类或者是危险的类(而且有惊人的许多这样的类)。

1

如果MemberwiseClone不存在,除了通过使用Reflection之外,对于任何可继承的类来说,除了要求每个派生类明确提供一个以外,没有任何方法支持多态克隆操作。派生类提供克隆操作失败会导致意外的行为。例如,假设Vehicle,Car和ToyotaCar提供了明确的克隆方法,但ToyotaCorolla没有。如果某人有ToyotaCorolla类型的对象并试图克隆它,则生成的对象将是ToyotaCar。由于存在需要多态克隆的情况,并且要求可克隆类的每个派生类提供明确的支持是不方便的,因此MemberwiseClone是该框架的必要部分。

另一方面,MemberwiseClone也可能是危险的。在对象上执行MemberwiseClone会频繁产生一个破碎的对象;试图使用破损对象的任何属性或方法可能会破坏原始文件。

这太糟糕了微软没有更好地定义克隆的良好做法。设计一个多态克隆模式是可能的,不需要继承类来明确地做任何事情,除非它们添加需要特殊处理的字段,或者除非调用者期望克隆方法的声明返回类型是派生类。虽然后一种情况经常会成为一种需求,但未明确实施必要的方法会产生编译时错误,而不是错误的运行时行为。

顺便说一句,微软似乎认为有关深层克隆和浅层克隆有点混淆。没有。在一个对象上调用“克隆”应该将对象克隆到任何深度,以获得其定义的语义。克隆FileCabinet(Of T)应该产生一个新的FileCabinet,就FileCabinet的方法而言,它独立于原始文件,但它应该与原始文件保持相同的T实例。由于文件柜的目的是保存T的实例,但不对其做任何事情,克隆内阁不应该暗示克隆内容(但它意味着克隆内阁自己用来保存内容的任何阵列)。

顺便说一句,如果我有我的dr drhers,那么在.NET中会有一个接口,由String和原始类型(以及其他许多元素)实现,称为DeepClonableIfMutable。当应用于String或其他基元时,DeepCloneIfMutable方法将简单地返回原始对象。用户定义的不可变对象可以实现DeepClonableIfMutableto类似的行为,而可变对象将深度克隆自己和任何嵌套的DeepClonableIfMutable实例。

2
  • 很多东西没有意义被克隆;任何会谈非托管手柄,例如
  • 大多数对象不需要克隆设施
  • 深拷贝东西正确真的硬,如果你去的几个简单的情况外
  • 在许多情况下,还有比盲目克隆
  • 更好的比喻手动添加克隆设施你的类型的需要是十分容易

对我来说,这是一个不费吹灰之力,这应该是不是被默认添加到公共API。

相关问题