"Deep Copy" e "Shallow Copy"

pubblicato il 28/08/2008

Quando vogliamo ottenere la copia di un oggetto, abbiamo a disposizione due modalità:

Shallow Copy

La copia Shallow (lett. superficiale), consente di ottenere una copia dell'oggetto di partenza con la copia delle proprietà di tipo Value; tuttavia le proprietà di tipo Reference puntano ancora agli stessi oggetti puntati dalle corrispondenti proprietà dell'oggetto sorgente della copia.

Deep Copy

La copia Deep (lett. profonda) invece consente di ottenere una copia nel senso più pieno del termine, quindi anche per le proprietà di tipo Reference verranno creati dei nuovi oggetti che conterranno gli stessi "valori" degli oggetti di partenza, ma saranno separati da questi.

Uno dei metodi più immediati per ottenere una Deep Copy consiste nel serializzare l'oggetto in memoria e poi de-serializzarlo nuovamente nel nuovo ogggetto "clone". Prerequisito fondamentale, ovviamente, è che l'oggetto da copiare sia serializzabile.

Namespace tmSoft.ObjectUtils

  Public Shared Function DeepClone(source As Object) As Object

    Dim binaryFormatter As System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
    Dim memStream As System.IO.MemoryStream = New System.IO.MemoryStream()

    binaryFormatter = New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(Nothing, New System.Runtime.Serialization.StreamingContext(System.Runtime.Serialization.StreamingContextStates.Clone))

    binaryFormatter.Serialize(memStream, source)

    memStream.Seek(0, System.IO.SeekOrigin.Begin)

    return binaryFormatter.Deserialize(memStream)   End Function

End Namespace

N.B.: Nello snippet qui presentato ho aggiunto tutte le namespace per mostrare da dove arrivano tutte le classi in gioco; nel codice reale avrei aggiunto delle belle Import... snellendo così il codice

A questo punto non resta che richiamare il metodo dalla classe che si vuole clonare; una buona pratica può essere quella di realizzare un'interfaccia (ICloneable, per esempio):

Public Interface ICloneable

  Public Function DeepClone(source as Object) As Object

End Interface

E quindi implementare l'interfaccia nella classe da clonare:

Public Class MyDeeplyCloneable

  Implements ICloneable

  Public Function DeepClone(source as Object) As Object

    Return tmSoft.ObjectUtils.DeepClone(Me)

  End Function

End Class