1. Introduzione
Spesso vi Γ¨ la necessitΓ di eseguire una copia dellβistanza della classe con cui si sta lavorando, ovvero la creazione di una nuova istanza di una classe con lo steso valore di unβistanza esistente.
La procedura di copia non Γ¨ unβoperazione banale che non puΓ² essere fatta con un assegnamento, in quanto le classi sono tipi di riferimento e conseguentemente, per esempio, questa operazione
object a = new object {foo="bar"}
object b = a
b.foo = "new bar" //anche a.foo = "new bar"
porta alla modifica dellβattributo foo
sia dellβoggetto a
che dellβoggetto b
.
2. Il metodo Object.MemberwiseClone()
Questo metodo Γ¨ un metodo di Object
e, conseguentemente, puΓ² essere applicato a tutti gli oggetti del nostro sistema.
In particolare il MemberwiseClone
metodo crea una copia superficiale (shallow copy) creando un nuovo oggetto e quindi copiando i campi non static dellβoggetto corrente al nuovo oggetto.
Se un campo Γ¨ di tipo:
- Valore*: viene eseguita una copia bit per bit del campo;
- Riferimento: viene copiato solo il riferimento pertanto sia lβoggetto originale che il suo clone fanno riferimento allo stesso oggetto.
Questo metodo Γ¨ il metodo base di tutti i metodi
clone()
, e viene utilizzato per la fase iniziale di shallow copy. A questo metodo deve spesso seguire unβimplementazione personalizzata al fine di ottenere la copia come desiderato (deep copy).
3. Lβinterfaccia ICloneable
Quando ho la necessitΓ di implementare un metodo clone()
che effettui una deep copy e che, conseguentemente, estenda il metodo MemberwiseClone
di object
posso implementare lβinterfaccia ICloneable
che contiene un solo metodo, Clone
, il quale fornisce un supporto della clonazione aggiuntivo a quello di Object.MemberwiseClone
.
Lβinterfaccia ICloneable
richiede semplicemente che lβimplementazione del valore restituito dal metodo Clone
ritorni una copia dellβistanza dellβoggetto corrente.
Non specifica se lβoperazione di duplicazione esegue una copia completa, una copia superficiale, o una via di mezzo, nΓ© richiede che tutti i valori della proprietΓ dellβistanza originale vengano copiati nella nuova istanza.
Tipicamente la struttura di una classe che implementa questa interfaccia Γ¨ la seguente:
public class ClassToClone : ICloneable
{
public object Clone()
{
ClassToClone clone = (ClassToClone) this.MemberwiseClone();
// logica di copia dei tipi di riferimento
return clone;
}
}
In ultima istanza specifico che il metodo clone
ritorna un tipo object
, come anche il metodo MemberwiseClone
, conseguentemente la loro chiamata deve sempre essere preceduta da un cast del tipo di variabile che si sta clonando.