I am back!
Dopo quasi due mesi di totale assenza (studio troppo..questo è il mio problema!
)!
Parliamo di come effettuare la copia di un oggetto con C#, prima però un pò di teoria!
Le tecniche per effettuare la copia di un oggetto sono essenzialmente due : Shallow copy e Deep copy.
La Shallow copy effettua una copia parziale di un oggetto mentre la Deep copy esegue una copia completa. Copia parziale vuol dire che con la shallow copy vengono copiati solo i campi con valore (ad esempio campi di tipo int) e non i campi con riferimenti (ad esempio campi di tipo oggetto in generale). Questo vuol dire che l'oggetto originale e la sua copia condivideranno i campi riferimento. Quindi, una modifica effettuata al riferimento, sarà visibile sia dall'oggetto originale che dalla sua copia...spesso questa cosa è inutile e/o scomoda!
Per effettuare una copia completamente indipendente dall'originale allora si fa ricorso alla deep copy.
Vediamo in C# come implementare sia la shallow copy che la deep copy!
Prendiamo, ad esempio, una classe Nodo che rappresenta appunto un nodo di un albero qualsiasi.
public class Nodo
{
public Nodo(string content)
{
this.Text = content;
this.Children = new List<Nodo>();
this.Parents = new List<Nodo>();
}
private string text;
public string Text
{
get { return text; }
set { text = value; }
}
private List<Nodo> parents;
internal List<Nodo> Parents
{
get { return parents; }
set { parents = value; }
}
private List<Nodo> children;
internal List<Nodo> Children
{
get { return children; }
set { children = value; }
}
public void AddChild(Nodo node)
{
this.Children.Add(node);
}
public void AddParent(Nodo node)
{
this.Parents.Add(node);
}
public void RemoveChild(int index)
{
if(this.Children.Count > index)
this.Children.RemoveAt(index);
}
public void RemoveParent(int index)
{
if(this.Parents.Count > index)
this.Parents.RemoveAt(index);
}
}
Questa classe ha una propretà di tipo string e due di tipo collection, questo vuol dire che la shallow copy non avrebbe senso perchè tutti i campi sarebbero in comune con la copia. Modificando la proprietà text della copia si modificherebbe anche l'originale.
Per chi fosse interessato, per la shallow copy :
Nodo root = new Nodo("originale");
Nodo root_copy = root; // shallow copy
root_copy.Text = "copia"; // questo imposta anche la proprietà text di root al valore "copia"!!!
Per effettuare la deep copy sfruttiamo la serializzazione...
Prima di tutto importiamo :
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
Poi aggiungiamo alla classe Nodo l'attributo : [Serializable] e facciamo ereditare da ICloneable.
Quindi dovremo avere :
[Serializable]
public class Nodo : ICloneable
{
public Nodo(string content)
{
this.Text = content;
this.Children = new List<Nodo>();
this.Parents = new List<Nodo>();
}
......
}
Aggiungiamo poi il metodo Clone() :
[Serializable]
public class Nodo : ICloneable
{
public Nodo(string content)
{
this.Text = content;
this.Children = new List<Nodo>();
this.Parents = new List<Nodo>();
}
......
public object Clone()
{
MemoryStream ms = new MemoryStream();
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(ms, this);
ms.Position = 0;
object obj = bf.Deserialize(ms);
ms.Close();
return obj;
}
}
Adesso possiamo effettuare la deep copy :
Nodo root = new Nodo("originale");
Nodo root_copy = (Nodo)root.Clone(); //deep copy
root_copy.Text = "copia"; // questo NON imposta anche la proprietà text di root al valore "copia" ma lascia "originale"!!! I due oggetti sono indipendenti.
L'interfaccia IClonable stabilisce che l'oggetto può essere duplicato. Ha un solo metodo :
public interface IClonable {
Object Clone();
}
Alla classe che eredita il compito di implementare questo metodo. Per la shallow copy è possibile sfruttare questa interfaccia in questo modo :
public object Clone()
{
return Memberwiseclone();
}
Mentre per la deep copy una implementazione possibile è quella vista in precedenza che si basa sulla serializzazione.
Questo è tutto per adesso
Enjoy!