Глубокое клонирование можно выполнить двумя способами: с помощью реализации ICloneable (и вызова метода Object.MemberwiseClone) или с помощью двоичной сериализации.
Первый путь
Первый (и, возможно, более быстрый, но не всегда лучший) способ заключается в реализации интерфейса ICloneable в каждом типе. Пример ниже иллюстрирует. Класс C реализует ICloneable, и, поскольку этот класс ссылается на другие классы D и E, последние также реализуют этот интерфейс. Внутри метода Clone в C мы вызываем метод 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
Теперь, когда вы вызываете метод Clone для экземпляра C, вы получаете глубокое клонирование этого экземпляра:
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 имеют ссылочные типы, вы должны реализовать их метод Clone, как мы это делали для класса C. И так далее.
Предупреждения:
1-образец выше действителен, пока нет круговой ссылки. Например, если класс C имеет собственную ссылку (например, поле типа C), реализация интерфейса ICloneable не будет легкой, поскольку метод Clone в C может войти в бесконечный цикл.
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!