过去我需要克隆对象,但却发现它们没有实现Clone()
方法,迫使我手动执行(创建一个新实例并从原始复制所有属性)到新的)
为什么克隆不像复制分配对象的内存块那么容易,因此在Clone
类中有object
方法,.NET中的所有类都继承它? / p>
答案 0 :(得分:24)
因为那不会执行深度克隆,通常克隆确实需要。想象一下,你有一个数组或列表的引用......只需复制你的对象所占用的内存就会克隆引用。通过克隆和原始对象可以看到对数组的任何更改 - 因此两个对象仍然连接,这违反了正常的克隆点。
如果您想要实现该功能,那很容易 - 这就是Object.MemberwiseClone()
的用途。大多数情况下,如果它甚至使有意义克隆一个对象(克隆NetworkStream
是什么意思?),克隆每个属性是有意义的......除非它引用一个不可变的换句话说,这是一个自然难以解决的问题,这就是大多数类型不支持克隆的原因。
如果你坚持使用不可变的类型,那就不是一个问题......这使得其他事情变得更加难以理解,但在很多情况下它可能非常强大。
答案 1 :(得分:7)
其他人已经解释了MemberwiseClone
,但没有人给出为什么受保护的解释。我会尽力给出理由。
这里的问题是MemberwiseClone
只是盲目地复制了州。在许多情况下,这是不可取的。例如,对象可能具有私有字段,该字段是对List
的引用。浅层副本(例如MemberwiseClone
所做的那样)会导致新对象指向同一个列表 - 并且可能会编写类而不期望列表与其他任何人共享。
或者一个对象可以有某种ID字段,在构造函数中生成 - 再次,当你克隆它时,你得到两个具有相同ID的对象,这可能会导致方法中的各种奇怪的失败,假设ID是唯一的
或者说你有一个打开套接字或文件流的对象,并存储对它的引用。 MemberwiseClone
只会复制引用 - 您可以想象试图将调用交错到同一个流的两个对象不会很好地结束。
简而言之,“克隆”不是任意对象的明确定义的操作。默认情况下,在C ++中为所有类提供成员operator=
这一事实更令人讨厌,因为人们常常忘记它存在,并且不会因复制没有意义的类禁用它,或者是危险的(并且有很多这样的课程。)
答案 2 :(得分:4)
有(至少)两种克隆。大多数参考文献都讨论了浅和深克隆,但实际上它们之间存在着色调。
关键问题是“应该复制多少”与“应分享多少”之间的紧张关系。
考虑一个Order
对象,其中包含对Customer
,Address
和List
OrderLines
的引用。
如果您想Clone()
Order
,有什么参与?
“只是复制内存块”会为您提供一个新的Order
,但会共享Customer
,Address
和List
} OrderLines
。 (请记住,对象成员是通过引用存储的,因此当您复制内存块时,最终会有两个对同一对象的引用)。
显然,您不希望在两个List
之间共享OrderLines
Order
。实际上,您可能也希望克隆每个OrderLine
。
如果您正在使用通用Clone()
方法,该方法将如何知道应该递归克隆哪些成员,哪些不应该?
一般来说,这是一个棘手的问题 - 这就是为什么单个对象可以根据情况实现适当的语义。
最后一点:即使我创建了Clone()
个对象的功能,我也不倾向于创建Clone()
方法,而是选择复制构造函数 - 一个接受另一个对象作为基础的构造函数。如果找不到Clone()
,请查找。
答案 3 :(得分:2)
有Object.MemberwiseClone(),之类的东西可以完成你描述的内容。它正在制作一个浅物体的副本。
它不会自动执行深度克隆...您需要手动调用所有成员对象上的克隆等。
答案 4 :(得分:0)
您必须在类中明确实现ICloneable接口。
但是,正如文档所述,MemberwiseClone中的克隆机制无法区分浅拷贝和深拷贝。