您可以通过两种方式进行深度克隆:通过实现 ICloneable(并调用 Object.MemberwiseClone 方法),或通过二进制序列化。
第一种方式
第一种(可能更快,但并不总是最好的)方法是在每种类型中实现 ICloneable 接口。下面的示例说明了这一点。C类实现了ICloneable,由于这个类引用了其他的D类和E类,那么后者也实现了这个接口。在 C 的 Clone 方法中,我们调用其他类型的 Clone 方法。
Public Class C
Implements ICloneable
Dim a As Integer
' Reference-type fields:
Dim d As D
Dim e As E
Private Function Clone() As Object Implements System.ICloneable.Clone
' Shallow copy:
Dim copy As C = CType(Me.MemberwiseClone, C)
' Deep copy: Copy the reference types of this object:
If copy.d IsNot Nothing Then copy.d = CType(d.Clone, D)
If copy.e IsNot Nothing Then copy.e = CType(e.Clone, E)
Return copy
End Function
End Class
Public Class D
Implements ICloneable
Public Function Clone() As Object Implements System.ICloneable.Clone
Return Me.MemberwiseClone()
End Function
End Class
Public Class E
Implements ICloneable
Public Function Clone() As Object Implements System.ICloneable.Clone
Return Me.MemberwiseClone()
End Function
End Class
现在,当您为 C 的实例调用 Clone 方法时,您将获得该实例的深度克隆:
Dim c1 As New C
Dim c2 As C = CType(c1.Clone, C) ' Deep cloning. c1 and c2 point to two different
' locations in memory, while their values are the
' same at the moment. Changing a value of one of
' these objects will NOT affect the other.
注意:如果 D 类和 E 类具有引用类型,则必须像我们对 C 类所做的那样实现它们的 Clone 方法。依此类推。
警告:1-只要没有循环引用,上面的示例就有效。例如,如果 C 类有一个自引用(例如,C 类型的字段),实现 ICloneable 接口并不容易,因为 C 中的 Clone 方法可能会进入无限循环。
2-另外需要注意的是,MemberwiseClone 方法是 Object 类的受保护方法。这意味着您只能在类的代码中使用此方法,如上所示。这意味着您不能将它用于外部类。
因此,实现 ICloneable 只有在上述两个警告不存在时才有效。否则,您应该使用二进制序列化技术。
第二种方式
二进制序列化可用于深度克隆而不会出现上述问题(尤其是循环引用)。这是一个使用二进制序列化执行深度克隆的通用方法:
Public Class Cloning
Public Shared Function DeepClone(Of T)(ByVal obj As T) As T
Using MStrm As New MemoryStream(100) ' Create a memory stream.
' Create a binary formatter:
Dim BF As New BinaryFormatter(Nothing, New StreamingContext(StreamingContextStates.Clone))
BF.Serialize(MStrm, obj) ' Serialize the object into MStrm.
' Seek the beginning of the stream, and then deserialize MStrm:
MStrm.Seek(0, SeekOrigin.Begin)
Return CType(BF.Deserialize(MStrm), T)
End Using
End Function
End Class
以下是如何使用此方法:
Dim c1 As New C
Dim c2 As C = Cloning.DeepClone(Of C)(c1) ' Deep cloning of c1 into c2. No need to
' worry about circular references!