In Visual Basic è spesso necessario creare una copia di un oggetto per modificare i dati in modo nuovo, senza influenzare la struttura originale. Si pone quindi la questione di differenziare la copia superficiale (shallow) dalla copia profonda (deep), soprattutto se gli oggetti contengono tipi di riferimento annidati.
Storia della questione:
La copia superficiale copia solo i valori delle proprietà primitive e i riferimenti agli oggetti annidati, mentre la copia profonda crea nuove istanze di tutti gli oggetti annidati. La differenza è fondamentale nel lavorare con dati complessi, ad esempio, se un oggetto contiene collezioni o altri oggetti.
Problema:
Se si copia un oggetto per riferimento o si utilizza il metodo standard MemberwiseClone, qualsiasi modifica agli oggetti annidati influenzerà la struttura originale insieme alla copia — questo è pericoloso per la logica aziendale e può portare a bug difficili da individuare.
Soluzione:
In VB.NET non esiste una copia profonda pronta all'uso, quindi deve essere implementata manualmente o tramite serializzazione. Solitamente si implementa un metodo personalizzato DeepCopy, creando nuove istanze di tutti gli oggetti annidati.
Esempio di codice per la copia superficiale e profonda:
Class Person Public Name As String Public Address As Address ' Copia superficiale Public Function ShallowCopy() As Person Return CType(Me.MemberwiseClone(), Person) End Function ' Copia profonda Public Function DeepCopy() As Person Dim copy As Person = CType(Me.MemberwiseClone(), Person) copy.Address = New Address() With {.City = Me.Address.City} Return copy End Function End Class Class Address Public City As String End Class
Caratteristiche chiave:
Cosa restituisce l'operatore = quando si copia un oggetto di una classe in Visual Basic?
Risposta: L'operatore = per i tipi di riferimento assegna un riferimento, non copia i valori. Pertanto, entrambe le variabili punteranno allo stesso oggetto.
Dim a As New Person() Dim b As Person = a ' Ora a e b sono riferimenti allo stesso oggetto
Si può usare MemberwiseClone per la copia profonda?
Risposta: No. Il metodo MemberwiseClone implementa solo la copia superficiale — tutti i tipi di riferimento annidati sono copiati per riferimento.
Perché la serializzazione non è sempre un modo universale per la copia profonda?
Risposta: La serializzazione funziona solo con oggetti serializzabili e potrebbe non supportare proprietà di tipo Object o non contrassegnate come Serializable. Inoltre, la serializzazione funziona più lentamente della copia standard.
Un cliente copia l'oggetto ordine con l'operatore = per creare un nuovo ordine, senza rendersi conto che l'elenco annidato degli articoli è condiviso tra entrambi gli oggetti.
Pro: Veloce, semplice
Contro: Modifiche in un ordine influenzano anche l'altro — errori critici nella gestione dei prodotti.
Un metodo DeepCopy è stato implementato per copiare l'ordine insieme a tutti i prodotti annidati e all'indirizzo di consegna.
Pro: Affidabile separazione dei dati, logica aziendale corretta
Contro: Necessità di prestare attenzione alla struttura dell'oggetto, più codice da mantenere