Come clonare gli oggetti

Quando faccio ciò che segue … qualsiasi cosa fatta a Persona b modifica Persona a (pensavo che fare questo clonasse Persona b da Persona a). Non ho nemmeno idea se cambiare persona a cambierà la Persona b dopo il collegamento. Grazie al mio codice adesso, posso vederlo solo in 1 direzione.

Person a = new Person() { head = "big", feet = "small" }; Person b = a; b.head = "small"; //now a.head = "small" too 

Ora se lo faccio invece .. La persona a diventa completamente separata.

 Person b = new Person() { head = a.head, feet = a.feet }; 

Ora questo fine e un po ‘ha senso quando si confronta questo comportamento con altre cose in C #. MA, questo potrebbe diventare molto fastidioso con oggetti di grandi dimensioni.

C’è un modo per collegarlo a tutti?

Ad esempio:

Person b = a.Values;

C’è un modo per collegarlo a tutti?

No, non proprio. Dovrai creare una nuova istanza per evitare che l’originale influenzi la “copia”. Ci sono un paio di opzioni per questo:

  1. Se il tuo tipo è una struct , non una class , verrà copiata per valore (invece di copiare semplicemente il riferimento all’istanza). Questo gli darà la semantica che stai descrivendo, ma ha molti altri effetti collaterali che tendono ad essere meno desiderabili, e non è raccomandato per nessun tipo mutabile (che ovviamente è, o questo non sarebbe un problema!)

  2. Implementa un meccanismo di “clonazione” sui tuoi tipi. Questo può essere ICloneable o anche solo un costruttore che prende un’istanza e ne copia i valori.

  3. Usa reflection, MemberwiseClone o simili per copiare tutti i valori, quindi non devi scrivere il codice per farlo. Questo ha potenziali problemi, specialmente se hai campi che contengono tipi non semplici.

Quello che stai cercando è una clonazione. Dovrai implementare IClonable e poi fare la clonazione.

Esempio:

 class Person() : ICloneable { public string head; public string feet; #region ICloneable Members public object Clone() { return this.MemberwiseClone(); } #endregion } 

Quindi puoi semplicemente chiamare il metodo Clone per fare una ShallowCopy (In questo caso particolare anche un DeepCopy )

 Person a = new Person() { head = "big", feet = "small" }; Person b = (Person) a.Clone(); 

È ansible utilizzare il metodo MemberwiseClone della class Object per eseguire la clonazione.

Io uso AutoMapper per questo. Funziona così:

 Mapper.CreateMap(typeof(Person), typeof(Person)); Mapper.Map(a, b); 

Ora la persona a ha tutte le proprietà della persona b.

Per inciso, AutoMapper funziona anche per oggetti diversi. Per maggiori informazioni, dai un’occhiata a http://automapper.org

Aggiornamento: io uso questa syntax ora (in modo semplicistico – in realtà i CreateMaps sono nei profili AutoMapper):

 Mapper.CreateMap; Mapper.Map(a, b); 

Nota che non devi fare una CreateMap per mappare un object dello stesso tipo a un altro, ma se non lo fai, AutoMapper creerà una copia superficiale, che significa al laico che se cambi un object, l’altro cambia anche.

Poiché il metodo MemberwiseClone () non è pubblico, ho creato questo semplice metodo di estensione per semplificare la clonazione degli oggetti:

 public static T Clone(this T obj) { var inst = obj.GetType().GetMethod("MemberwiseClone", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); return (T)inst?.Invoke(obj, null); } 

Uso:

 var clone = myObject.Clone(); 

Per clonare il tuo object di class puoi usare il metodo Object.MemberwiseClone,

aggiungi questa funzione alla tua class:

 public class yourClass { // ... // ... public yourClass DeepCopy() { yourClass othercopy = (yourClass)this.MemberwiseClone(); return othercopy; } } 

quindi per eseguire una copia indipendente, basta chiamare il metodo DeepCopy:

 yourClass newLine = oldLine.DeepCopy(); 

b sono solo due riferimenti allo stesso object Person. Entrambi sostengono essenzialmente l’indirizzo della Person .

Esiste un’interfaccia IConeable , anche se relativamente poche classi lo supportano. Con questo, scriveresti:

 Person b = a.Clone(); 

Quindi, b sarebbe una Person completamente separata.

Potresti anche implementare un costruttore di copie:

 public Person(Person src) { // ... } 

Non esiste un modo integrato per copiare tutti i campi. Puoi farlo attraverso il riflesso, ma ci sarebbe una penalità per le prestazioni.

Potresti farlo in questo modo:

 var jss = new JavaScriptSerializer(); var b = jss.Deserialize(jss.Serialize(a)); 

Per la clonazione profonda potresti dare un’occhiata a questa risposta: https://stackoverflow.com/a/78612/550975

  public static T Clone(T obj) { DataContractSerializer dcSer = new DataContractSerializer(obj.GetType()); MemoryStream memoryStream = new MemoryStream(); dcSer.WriteObject(memoryStream, obj); memoryStream.Position = 0; T newObject = (T)dcSer.ReadObject(memoryStream); return newObject; } 

Senza dolore: utilizzando la libreria NClone

 Person a = new Person() { head = "big", feet = "small" }; Person b = Clone.ObjectGraph(a); 

Questo accade perché “Persona” è una class, quindi viene passata per riferimento. Nella dichiarazione “b = a” stai solo copiando un riferimento all’unica istanza “Persona” che hai creato con la parola chiave new.

Il modo più semplice per avere il comportamento che stai cercando è usare un “tipo di valore”.

Basta cambiare la dichiarazione della persona da

 class Person 

a

 struct Person