Oggetti di clonazione profonda

Voglio fare qualcosa come:

MyObject myObj = GetMyObj(); // Create and fill a new object MyObject newObj = myObj.Clone(); 

E quindi apportare modifiche al nuovo object che non si riflettono nell’object originale.

Non ho spesso bisogno di questa funzionalità, quindi quando è stato necessario, ho fatto ricorso alla creazione di un nuovo object e quindi a copiare ciascuna proprietà singolarmente, ma mi lascia sempre la sensazione che esista un modo migliore o più elegante di gestire la situazione.

Come posso clonare o copiare in profondità un object in modo che l’object clonato possa essere modificato senza che nessuna modifica venga riflessa nell’object originale?

Mentre la pratica standard è quella di implementare l’interfaccia ICloneable ( qui descritta, quindi non voglio rigurgitare), ecco una copiatrice di oggetti clone profonda che ho trovato su The Code Project qualche tempo fa e l’ho incorporata nelle nostre cose.

Come accennato altrove, richiede che i tuoi oggetti siano serializzabili.

 using System; using System.IO; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; ///  /// Reference Article http://www.codeproject.com/KB/tips/SerializedObjectCloner.aspx /// Provides a method for performing a deep copy of an object. /// Binary Serialization is used to perform the copy. ///  public static class ObjectCopier { ///  /// Perform a deep Copy of the object. ///  /// The type of object being copied. /// The object instance to copy. /// The copied object. public static T Clone(T source) { if (!typeof(T).IsSerializable) { throw new ArgumentException("The type must be serializable.", "source"); } // Don't serialize a null object, simply return the default for that object if (Object.ReferenceEquals(source, null)) { return default(T); } IFormatter formatter = new BinaryFormatter(); Stream stream = new MemoryStream(); using (stream) { formatter.Serialize(stream, source); stream.Seek(0, SeekOrigin.Begin); return (T)formatter.Deserialize(stream); } } } 

L’idea è che serializza il tuo object e poi lo deserializza in un nuovo object. Il vantaggio è che non devi preoccuparti di clonare tutto quando un object diventa troppo complesso.

E con l’uso di metodi di estensione (anche dalla fonte di riferimento originale):

Se si preferisce utilizzare i nuovi metodi di estensione di C # 3.0, cambiare il metodo per ottenere la seguente firma:

 public static T Clone(this T source) { //... } 

Ora la chiamata al metodo diventa semplicemente objectBeingCloned.Clone(); .

EDIT (10 gennaio 2015) Ho pensato di rivisitare questo, per dire che recentemente ho iniziato a usare (Newtonsoft) Json per farlo, dovrebbe essere più leggero ed evitare il sovraccarico dei tag [Serializable]. ( NB @atconway ha sottolineato nei commenti che i membri privati ​​non vengono clonati usando il metodo JSON)

 ///  /// Perform a deep Copy of the object, using Json as a serialisation method. NOTE: Private members are not cloned using this method. ///  /// The type of object being copied. /// The object instance to copy. /// The copied object. public static T CloneJson(this T source) { // Don't serialize a null object, simply return the default for that object if (Object.ReferenceEquals(source, null)) { return default(T); } // initialize inner objects individually // for example in default constructor some list property initialized with some values, // but in 'source' these items are cleaned - // without ObjectCreationHandling.Replace default constructor values will be added to result var deserializeSettings = new JsonSerializerSettings {ObjectCreationHandling = ObjectCreationHandling.Replace}; return JsonConvert.DeserializeObject(JsonConvert.SerializeObject(source), deserializeSettings); } 

Volevo un cloner per oggetti molto semplici, per lo più primitivi e liste. Se il tuo object è fuori dalla scatola serializzabile in JSON, allora questo metodo farà il trucco. Ciò non richiede alcuna modifica o implementazione di interfacce sulla class clonata, ma solo un serializzatore JSON come JSON.NET.

 public static T Clone(T source) { var serialized = JsonConvert.SerializeObject(source); return JsonConvert.DeserializeObject(serialized); } 

La ragione per non usare ICloneable non è perché non ha un’interfaccia generica. La ragione per non usarlo è perché è vaga . Non è chiaro se stai ricevendo una copia superficiale o profonda; questo dipende dall’implementatore.

Sì, MemberwiseClone fa una copia superficiale, ma il contrario di MemberwiseClone non è Clone ; sarebbe, forse, DeepClone , che non esiste. Quando si utilizza un object attraverso la sua interfaccia ICloneable, non si può sapere quale tipo di clonazione viene eseguita dall’object sottostante. (E i commenti XML non lo renderanno chiaro, perché otterrete i commenti dell’interfaccia piuttosto che quelli sul metodo Clone dell’object.)

Quello che faccio di solito è semplicemente fare un metodo di Copy che fa esattamente quello che voglio.

Dopo molte letture su molte delle opzioni collegate qui, e possibili soluzioni per questo problema, credo che tutte le opzioni siano sintetizzate abbastanza bene al link di Ian P (tutte le altre opzioni sono variazioni di quelle) e la migliore soluzione è fornita da Il link di Pedro77 sui commenti delle domande.

Quindi copro solo le parti rilevanti di questi 2 riferimenti qui. In questo modo possiamo avere:

La cosa migliore da fare per la clonazione di oggetti in c sharp!

Innanzitutto, quelle sono tutte le nostre opzioni:

  • Manualmente con ICloneable , che è Shallow e non Type-Safe
  • MemberwiseClone , che utilizza ICloneable
  • Riflessione utilizzando Activator.CreateInstance e MemberwiseClone ricorsivo
  • Serializzazione , come indicato dalla risposta preferita di johnc
  • Intermediate Language , di cui non ho idea di come funzioni
  • Metodi di estensione , come questo framework clone personalizzato di Havard Straden
  • Alberi di espressione

L’ articolo Fast Deep Copy di Expression Trees ha anche un confronto delle prestazioni della clonazione tramite Serialization, Reflection ed Expression Trees.

Perché scelgo ICloneable (cioè manualmente)

Mr Venkat Subramaniam (link ridondante qui) spiega in molti dettagli perché .

Tutto il suo articolo circonda un esempio che cerca di essere applicabile per la maggior parte dei casi, utilizzando 3 oggetti: Person , Brain e City . Vogliamo clonare una persona, che avrà il suo cervello ma la stessa città. È ansible visualizzare tutti i problemi uno qualsiasi degli altri metodi sopra riportati può portare o leggere l’articolo.

Questa è la mia versione leggermente modificata della sua conclusione:

Copiare un object specificando New seguito dal nome della class porta spesso a un codice che non è estensibile. L’uso del clone, l’applicazione del modello prototipo, è un modo migliore per raggiungere questo objective. Tuttavia, l’uso del clone come è fornito in C # (e Java) può essere piuttosto problematico. È meglio fornire un costruttore di copia protetto (non pubblico) e invocarlo dal metodo clone. Questo ci dà la possibilità di debind il compito di creare un object a un’istanza di una class stessa, fornendo così estensibilità e anche, creando in sicurezza gli oggetti usando il costruttore di copia protetta.

Speriamo che questa implementazione possa chiarire le cose:

 public class Person : ICloneable { private final Brain brain; // brain is final since I do not want // any transplant on it once created! private int age; public Person(Brain aBrain, int theAge) { brain = aBrain; age = theAge; } protected Person(Person another) { Brain refBrain = null; try { refBrain = (Brain) another.brain.clone(); // You can set the brain in the constructor } catch(CloneNotSupportedException e) {} brain = refBrain; age = another.age; } public String toString() { return "This is person with " + brain; // Not meant to sound rude as it reads! } public Object clone() { return new Person(this); } … } 

Ora considera che una class deriva da Person.

 public class SkilledPerson extends Person { private String theSkills; public SkilledPerson(Brain aBrain, int theAge, String skills) { super(aBrain, theAge); theSkills = skills; } protected SkilledPerson(SkilledPerson another) { super(another); theSkills = another.theSkills; } public Object clone() { return new SkilledPerson(this); } public String toString() { return "SkilledPerson: " + super.toString(); } } 

Puoi provare a eseguire il seguente codice:

 public class User { public static void play(Person p) { Person another = (Person) p.clone(); System.out.println(p); System.out.println(another); } public static void main(String[] args) { Person sam = new Person(new Brain(), 1); play(sam); SkilledPerson bob = new SkilledPerson(new SmarterBrain(), 1, "Writer"); play(bob); } } 

L’output prodotto sarà:

 This is person with [email protected] This is person with [email protected] SkilledPerson: This is person with [email protected] SkilledPerson: This is person with [email protected] 

Osserva che, se teniamo un conteggio del numero di oggetti, il clone come implementato qui manterrà un conteggio corretto del numero di oggetti.

Preferisco un costruttore di copia a un clone. L’intento è più chiaro.

Semplice metodo di estensione per copiare tutte le proprietà pubbliche. Funziona per qualsiasi object e non richiede che la class sia [Serializable] . Può essere esteso per altri livelli di accesso.

 public static void CopyTo( this object S, object T ) { foreach( var pS in S.GetType().GetProperties() ) { foreach( var pT in T.GetType().GetProperties() ) { if( pT.Name != pS.Name ) continue; ( pT.GetSetMethod() ).Invoke( T, new object[] { pS.GetGetMethod().Invoke( S, null ) } ); } }; } 

Beh, stavo avendo problemi con l’uso di ICloneable in Silverlight, ma mi piaceva l’idea della seralizzazione, posso seralizzare l’XML, così ho fatto questo:

 static public class SerializeHelper { //Michael White, Holly Springs Consulting, 2009 //[email protected] public static T DeserializeXML(string xmlData) where T:new() { if (string.IsNullOrEmpty(xmlData)) return default(T); TextReader tr = new StringReader(xmlData); T DocItms = new T(); XmlSerializer xms = new XmlSerializer(DocItms.GetType()); DocItms = (T)xms.Deserialize(tr); return DocItms == null ? default(T) : DocItms; } public static string SeralizeObjectToXML(T xmlObject) { StringBuilder sbTR = new StringBuilder(); XmlSerializer xmsTR = new XmlSerializer(xmlObject.GetType()); XmlWriterSettings xwsTR = new XmlWriterSettings(); XmlWriter xmwTR = XmlWriter.Create(sbTR, xwsTR); xmsTR.Serialize(xmwTR,xmlObject); return sbTR.ToString(); } public static T CloneObject(T objClone) where T:new() { string GetString = SerializeHelper.SeralizeObjectToXML(objClone); return SerializeHelper.DeserializeXML(GetString); } } 

Se stai già utilizzando un’applicazione di terze parti come ValueInjecter o Automapper , puoi fare qualcosa del genere:

 MyObject oldObj; // The existing object to clone MyObject newObj = new MyObject(); newObj.InjectFrom(oldObj); // Using ValueInjecter syntax 

Usando questo metodo non devi implementare ISerializable o ICloneable sui tuoi oggetti. Questo è comune con il pattern MVC / MVVM, quindi sono stati creati strumenti semplici come questo.

vedere la soluzione di clonazione profonda valueinjecter su CodePlex .

Ho appena creato il progetto di libreria CloneExtensions . Esegue cloni veloci e profondi utilizzando semplici operazioni di assegnazione generate dalla compilazione del codice runtime di Expression Tree.

Come usarlo?

Invece di scrivere i propri metodi di Clone o Copy con un tono di assegnazione tra campi e proprietà, fai in modo che il programma lo faccia da solo, usando Expression Tree. GetClone() contrassegnato come metodo di estensione consente di chiamarlo semplicemente GetClone() :

 var newInstance = source.GetClone(); 

Puoi scegliere cosa copiare da source a newInstance usando CloningFlags :

 var newInstance = source.GetClone(CloningFlags.Properties | CloningFlags.CollectionItems); 

Cosa può essere clonato?

  • Primitive (int, uint, byte, double, char, ecc.), Tipi immutabili noti (DateTime, TimeSpan, String) e delegati (inclusi Action, Func, ecc.)
  • nullable
  • T [] array
  • Classi e strutture personalizzate, incluse classi e strutture generiche.

I membri della class / struct seguenti sono clonati internamente:

  • Valori dei campi pubblici, non di sola lettura
  • Valori delle proprietà pubbliche con get e set accessors
  • Elementi di raccolta per i tipi che implementano ICollection

Quanto è veloce?

La soluzione è più veloce della riflessione, poiché le informazioni sui membri devono essere raccolte una sola volta, prima che GetClone venga utilizzato per la prima volta per il tipo T .

È anche più veloce della soluzione basata sulla serializzazione quando cloni di più, quindi accoppia le istanze dello stesso tipo T

e altro ancora …

Ulteriori informazioni sulle espressioni generate sulla documentazione .

Elenco di debug di espressioni di esempio per List :

 .Lambda #Lambda1( System.Collections.Generic.List`1[System.Int32] $source, CloneExtensions.CloningFlags $flags, System.Collections.Generic.IDictionary`2[System.Type,System.Func`2[System.Object,System.Object]] $initializers) { .Block(System.Collections.Generic.List`1[System.Int32] $target) { .If ($source == null) { .Return #Label1 { null } } .Else { .Default(System.Void) }; .If ( .Call $initializers.ContainsKey(.Constant(System.Collections.Generic.List`1[System.Int32])) ) { $target = (System.Collections.Generic.List`1[System.Int32]).Call ($initializers.Item[.Constant(System.Collections.Generic.List`1[System.Int32])] ).Invoke((System.Object)$source) } .Else { $target = .New System.Collections.Generic.List`1[System.Int32]() }; .If ( ((System.Byte)$flags & (System.Byte).Constant(Fields)) == (System.Byte).Constant(Fields) ) { .Default(System.Void) } .Else { .Default(System.Void) }; .If ( ((System.Byte)$flags & (System.Byte).Constant(Properties)) == (System.Byte).Constant(Properties) ) { .Block() { $target.Capacity = .Call CloneExtensions.CloneFactory.GetClone( $source.Capacity, $flags, $initializers) } } .Else { .Default(System.Void) }; .If ( ((System.Byte)$flags & (System.Byte).Constant(CollectionItems)) == (System.Byte).Constant(CollectionItems) ) { .Block( System.Collections.Generic.IEnumerator`1[System.Int32] $var1, System.Collections.Generic.ICollection`1[System.Int32] $var2) { $var1 = (System.Collections.Generic.IEnumerator`1[System.Int32]).Call $source.GetEnumerator(); $var2 = (System.Collections.Generic.ICollection`1[System.Int32])$target; .Loop { .If (.Call $var1.MoveNext() != False) { .Call $var2.Add(.Call CloneExtensions.CloneFactory.GetClone( $var1.Current, $flags, $initializers)) } .Else { .Break #Label2 { } } } .LabelTarget #Label2: } } .Else { .Default(System.Void) }; .Label $target .LabelTarget #Label1: } 

}

cosa ha lo stesso significato del seguente codice c #:

 (source, flags, initializers) => { if(source == null) return null; if(initializers.ContainsKey(typeof(List)) target = (List)initializers[typeof(List)].Invoke((object)source); else target = new List(); if((flags & CloningFlags.Properties) == CloningFlags.Properties) { target.Capacity = target.Capacity.GetClone(flags, initializers); } if((flags & CloningFlags.CollectionItems) == CloningFlags.CollectionItems) { var targetCollection = (ICollection)target; foreach(var item in (ICollection)source) { targetCollection.Add(item.Clone(flags, initializers)); } } return target; } 

Non è proprio come scriverebbe il tuo metodo Clone per List ?

La risposta breve è ereditata dall’interfaccia ICloneable e quindi implementa la funzione .clone. Il clone deve eseguire una copia membro ed eseguire una copia profonda su qualsiasi membro che lo richiede, quindi restituire l’object risultante. Questa è un’operazione ricorsiva (richiede che tutti i membri della class che si desidera clonare siano o tipi di valore o implementino ICloneable e che i loro membri siano o tipi di valore o implementino ICloneable e così via).

Per una spiegazione più dettagliata sulla clonazione usando ICloneable, consulta questo articolo .

La lunga risposta è “dipende”. Come menzionato da altri, ICloneable non è supportato dai generici, richiede considerazioni speciali per i riferimenti alle classi circolari ed è visto da alcuni come un “errore” in .NET Framework. Il metodo di serializzazione dipende dal fatto che i tuoi oggetti siano serializzabili, che potrebbero non essere e potresti non avere alcun controllo. C’è ancora molto dibattito nella comunità su cui si basa la pratica “migliore”. In realtà, nessuna delle soluzioni è la misura unica, adatta a tutte le migliori pratiche per tutte le situazioni in cui ICloneable è stato inizialmente interpretato.

Vedi l’ articolo sull’angolo dello sviluppatore per alcune altre opzioni (credito a Ian).

Se vuoi la vera clonazione a tipi sconosciuti puoi dare un’occhiata a fastclone .

Questa è la clonazione basata su espressioni che funziona circa 10 volte più velocemente della serializzazione binaria e mantiene l’integrità completa del grafico degli oggetti.

Ciò significa: se ti riferisci più volte allo stesso object nella tua gerarchia, il clone avrà anche una singola istanza referenziata.

Non sono necessarie interfacce, attributi o altre modifiche agli oggetti da clonare.

La cosa migliore è implementare un metodo di estensione come

 public static T DeepClone(this T originalObject) { /* the cloning code */ } 

e quindi utilizzarlo ovunque nella soluzione

 var copy = anyObject.DeepClone(); 

Possiamo avere le seguenti tre implementazioni:

  1. Per serializzazione (il codice più breve)
  2. Con Reflection5 volte più veloce
  3. Da Expression Trees20 volte più veloce

Tutti i metodi collegati funzionano bene e sono stati profondamente testati.

  1. Fondamentalmente è necessario implementare l’interfaccia ICloneable e quindi realizzare la copia della struttura degli oggetti.
  2. Se è una copia profonda di tutti i membri, è necessario assicurare (non riferendosi alla soluzione che si sceglie) che tutti i bambini siano clonabili.
  3. A volte è necessario essere consapevoli di alcune limitazioni durante questo processo, ad esempio se copi gli oggetti ORM la maggior parte dei framework consente solo un object collegato alla sessione e NON DEVE fare cloni di questo object, o se è ansible che tu debba preoccuparti riguardo al collegamento di sessione di questi oggetti.

Saluti.

Mi è venuto in mente questo per superare un problema di .NET che deve copiare manualmente la lista .

Io uso questo:

 static public IEnumerable CloneList(List spotPlacements) { foreach (SpotPlacement sp in spotPlacements) { yield return (SpotPlacement)sp.Clone(); } } 

E in un altro posto:

 public object Clone() { OrderItem newOrderItem = new OrderItem(); ... newOrderItem._exactPlacements.AddRange(SpotPlacement.CloneList(_exactPlacements)); ... return newOrderItem; } 

Ho provato a creare oneliner che lo fa, ma non è ansible, a causa del rendimento che non funziona all’interno di blocchi di metodi anonimi.

Meglio ancora, usa il cloner Elenco generico:

 class Utility where T : ICloneable { static public IEnumerable CloneList(List tl) { foreach (T t in tl) { yield return (T)t.Clone(); } } } 

Keep things simple and use AutoMapper as others mentioned, it’s a simple little library to map one object to another… To copy an object to another with the same type, all you need is three lines of code:

 MyType source = new MyType(); Mapper.CreateMap(); MyType target = Mapper.Map(source); 

The target object is now a copy of the source object. Not simple enough? Create an extension method to use everywhere in your solution:

 public static T Copy(this T source) { T copy = default(T); Mapper.CreateMap(); copy = Mapper.Map(source); return copy; } 

By using the extension method, the three lines become one line:

 MyType copy = source.Copy(); 

In general, you implement the ICloneable interface and implement Clone yourself. C# objects have a built-in MemberwiseClone method that performs a shallow copy that can help you out for all the primitives.

For a deep copy, there is no way it can know how to automatically do it.

I’ve seen it implemented through reflection as well. Basically there was a method that would iterate through the members of an object and appropriately copy them to the new object. When it reached reference types or collections I think it did a recursive call on itself. Reflection is expensive, but it worked pretty well.

Here is a deep copy implementation:

 public static object CloneObject(object opSource) { //grab the type and create a new instance of that type Type opSourceType = opSource.GetType(); object opTarget = CreateInstanceOfType(opSourceType); //grab the properties PropertyInfo[] opPropertyInfo = opSourceType.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); //iterate over the properties and if it has a 'set' method assign it from the source TO the target foreach (PropertyInfo item in opPropertyInfo) { if (item.CanWrite) { //value types can simply be 'set' if (item.PropertyType.IsValueType || item.PropertyType.IsEnum || item.PropertyType.Equals(typeof(System.String))) { item.SetValue(opTarget, item.GetValue(opSource, null), null); } //object/complex types need to recursively call this method until the end of the tree is reached else { object opPropertyValue = item.GetValue(opSource, null); if (opPropertyValue == null) { item.SetValue(opTarget, null, null); } else { item.SetValue(opTarget, CloneObject(opPropertyValue), null); } } } } //return the new item return opTarget; } 

Q. Why would I choose this answer?

  • Choose this answer if you want the fastest speed .NET is capable of.
  • Ignore this answer if you want a really, really easy method of cloning.

In other words, go with another answer unless you have a performance bottleneck that needs fixing, and you can prove it with a profiler .

10x faster than other methods

The following method of performing a deep clone is:

  • 10x faster than anything that involves serialization/deserialization;
  • Pretty darn close to the theoretical maximum speed .NET is capable of.

And the method …

For ultimate speed, you can use Nested MemberwiseClone to do a deep copy . Its almost the same speed as copying a value struct, and is much faster than (a) reflection or (b) serialization (as described in other answers on this page).

Note that if you use Nested MemberwiseClone for a deep copy , you have to manually implement a ShallowCopy for each nested level in the class, and a DeepCopy which calls all said ShallowCopy methods to create a complete clone. This is simple: only a few lines in total, see the demo code below.

Here is the output of the code showing the relative performance difference for 100,000 clones:

  • 1.08 seconds for Nested MemberwiseClone on nested structs
  • 4.77 seconds for Nested MemberwiseClone on nested classs
  • 39.93 seconds for Serialization/Deserialization

Using Nested MemberwiseClone on a class almost as fast as copying a struct, and copying a struct is pretty darn close to the theoretical maximum speed .NET is capable of.

 Demo 1 of shallow and deep copy, using classs and MemberwiseClone: Create Bob Bob.Age=30, Bob.Purchase.Description=Lamborghini Clone Bob >> BobsSon Adjust BobsSon details BobsSon.Age=2, BobsSon.Purchase.Description=Toy car Proof of deep copy: If BobsSon is a true clone, then adjusting BobsSon details will not affect Bob: Bob.Age=30, Bob.Purchase.Description=Lamborghini Elapsed time: 00:00:04.7795670,30000000 Demo 2 of shallow and deep copy, using structs and value copying: Create Bob Bob.Age=30, Bob.Purchase.Description=Lamborghini Clone Bob >> BobsSon Adjust BobsSon details: BobsSon.Age=2, BobsSon.Purchase.Description=Toy car Proof of deep copy: If BobsSon is a true clone, then adjusting BobsSon details will not affect Bob: Bob.Age=30, Bob.Purchase.Description=Lamborghini Elapsed time: 00:00:01.0875454,30000000 Demo 3 of deep copy, using class and serialize/deserialize: Elapsed time: 00:00:39.9339425,30000000 

To understand how to do a deep copy using MemberwiseCopy, here is the demo project that was used to generate the times above:

 // Nested MemberwiseClone example. // Added to demo how to deep copy a reference class. [Serializable] // Not required if using MemberwiseClone, only used for speed comparison using serialization. public class Person { public Person(int age, string description) { this.Age = age; this.Purchase.Description = description; } [Serializable] // Not required if using MemberwiseClone public class PurchaseType { public string Description; public PurchaseType ShallowCopy() { return (PurchaseType)this.MemberwiseClone(); } } public PurchaseType Purchase = new PurchaseType(); public int Age; // Add this if using nested MemberwiseClone. // This is a class, which is a reference type, so cloning is more difficult. public Person ShallowCopy() { return (Person)this.MemberwiseClone(); } // Add this if using nested MemberwiseClone. // This is a class, which is a reference type, so cloning is more difficult. public Person DeepCopy() { // Clone the root ... Person other = (Person) this.MemberwiseClone(); // ... then clone the nested class. other.Purchase = this.Purchase.ShallowCopy(); return other; } } // Added to demo how to copy a value struct (this is easy - a deep copy happens by default) public struct PersonStruct { public PersonStruct(int age, string description) { this.Age = age; this.Purchase.Description = description; } public struct PurchaseType { public string Description; } public PurchaseType Purchase; public int Age; // This is a struct, which is a value type, so everything is a clone by default. public PersonStruct ShallowCopy() { return (PersonStruct)this; } // This is a struct, which is a value type, so everything is a clone by default. public PersonStruct DeepCopy() { return (PersonStruct)this; } } // Added only for a speed comparison. public class MyDeepCopy { public static T DeepCopy(T obj) { object result = null; using (var ms = new MemoryStream()) { var formatter = new BinaryFormatter(); formatter.Serialize(ms, obj); ms.Position = 0; result = (T)formatter.Deserialize(ms); ms.Close(); } return (T)result; } } 

Then, call the demo from main:

 void MyMain(string[] args) { { Console.Write("Demo 1 of shallow and deep copy, using classs and MemberwiseCopy:\n"); var Bob = new Person(30, "Lamborghini"); Console.Write(" Create Bob\n"); Console.Write(" Bob.Age={0}, Bob.Purchase.Description={1}\n", Bob.Age, Bob.Purchase.Description); Console.Write(" Clone Bob >> BobsSon\n"); var BobsSon = Bob.DeepCopy(); Console.Write(" Adjust BobsSon details\n"); BobsSon.Age = 2; BobsSon.Purchase.Description = "Toy car"; Console.Write(" BobsSon.Age={0}, BobsSon.Purchase.Description={1}\n", BobsSon.Age, BobsSon.Purchase.Description); Console.Write(" Proof of deep copy: If BobsSon is a true clone, then adjusting BobsSon details will not affect Bob:\n"); Console.Write(" Bob.Age={0}, Bob.Purchase.Description={1}\n", Bob.Age, Bob.Purchase.Description); Debug.Assert(Bob.Age == 30); Debug.Assert(Bob.Purchase.Description == "Lamborghini"); var sw = new Stopwatch(); sw.Start(); int total = 0; for (int i = 0; i < 100000; i++) { var n = Bob.DeepCopy(); total += n.Age; } Console.Write(" Elapsed time: {0},{1}\n\n", sw.Elapsed, total); } { Console.Write("Demo 2 of shallow and deep copy, using structs:\n"); var Bob = new PersonStruct(30, "Lamborghini"); Console.Write(" Create Bob\n"); Console.Write(" Bob.Age={0}, Bob.Purchase.Description={1}\n", Bob.Age, Bob.Purchase.Description); Console.Write(" Clone Bob >> BobsSon\n"); var BobsSon = Bob.DeepCopy(); Console.Write(" Adjust BobsSon details:\n"); BobsSon.Age = 2; BobsSon.Purchase.Description = "Toy car"; Console.Write(" BobsSon.Age={0}, BobsSon.Purchase.Description={1}\n", BobsSon.Age, BobsSon.Purchase.Description); Console.Write(" Proof of deep copy: If BobsSon is a true clone, then adjusting BobsSon details will not affect Bob:\n"); Console.Write(" Bob.Age={0}, Bob.Purchase.Description={1}\n", Bob.Age, Bob.Purchase.Description); Debug.Assert(Bob.Age == 30); Debug.Assert(Bob.Purchase.Description == "Lamborghini"); var sw = new Stopwatch(); sw.Start(); int total = 0; for (int i = 0; i < 100000; i++) { var n = Bob.DeepCopy(); total += n.Age; } Console.Write(" Elapsed time: {0},{1}\n\n", sw.Elapsed, total); } { Console.Write("Demo 3 of deep copy, using class and serialize/deserialize:\n"); int total = 0; var sw = new Stopwatch(); sw.Start(); var Bob = new Person(30, "Lamborghini"); for (int i = 0; i < 100000; i++) { var BobsSon = MyDeepCopy.DeepCopy(Bob); total += BobsSon.Age; } Console.Write(" Elapsed time: {0},{1}\n", sw.Elapsed, total); } Console.ReadKey(); } 

Again, note that if you use Nested MemberwiseClone for a deep copy , you have to manually implement a ShallowCopy for each nested level in the class, and a DeepCopy which calls all said ShallowCopy methods to create a complete clone. This is simple: only a few lines in total, see the demo code above.

Value types vs. References Types

Note that when it comes to cloning an object, there is is a big difference between a ” struct ” and a ” class “:

  • If you have a ” struct “, it’s a value type so you can just copy it, and the contents will be cloned (but it will only make a shallow clone unless you use the techniques in this post).
  • If you have a ” class “, it’s a reference type , so if you copy it, all you are doing is copying the pointer to it. To create a true clone, you have to be more creative, and use differences between value types and references types which creates another copy of the original object in memory.

See differences between value types and references types .

Checksums to aid in debugging

  • Cloning objects incorrectly can lead to very difficult-to-pin-down bugs. In production code, I tend to implement a checksum to double check that the object has been cloned properly, and hasn’t been corrupted by another reference to it. This checksum can be switched off in Release mode.
  • I find this method quite useful: often, you only want to clone parts of the object, not the entire thing.

Really useful for decoupling many threads from many other threads

One excellent use case for this code is feeding clones of a nested class or struct into a queue, to implement the producer / consumer pattern.

  • We can have one (or more) threads modifying a class that they own, then pushing a complete copy of this class into a ConcurrentQueue .
  • We then have one (or more) threads pulling copies of these classs out and dealing with them.

This works extremely well in practice, and allows us to decouple many threads (the producers) from one or more threads (the consumers).

And this method is blindingly fast too: if we use nested structs, it’s 35x faster than serializing/deserializing nested classs, and allows us to take advantage of all of the threads available on the machine.

Aggiornare

Apparently, ExpressMapper is as fast, if not faster, than hand coding such as above. I might have to see how they compare with a profiler.

As I couldn’t find a cloner that meets all my requirements in different projects, I created a deep cloner that can be configured and adapted to different code structures instead of adapting my code to meet the cloners requirements. Its achieved by adding annotations to the code that shall be cloned or you just leave the code as it is to have the default behaviour. It uses reflection, type caches and is based on fasterflect . The cloning process is very fast for a huge amount of data and a high object hierarchy (compared to other reflection/serialization based algorithms).

https://github.com/kalisohn/CloneBehave

Also available as a nuget package: https://www.nuget.org/packages/Clone.Behave/1.0.0

For example: The following code will deepClone Address, but only perform a shallow copy of the _currentJob field.

 public class Person { [DeepClone(DeepCloneBehavior.Shallow)] private Job _currentJob; public string Name { get; set; } public Job CurrentJob { get{ return _currentJob; } set{ _currentJob = value; } } public Person Manager { get; set; } } public class Address { public Person PersonLivingHere { get; set; } } Address adr = new Address(); adr.PersonLivingHere = new Person("John"); adr.PersonLivingHere.BestFriend = new Person("James"); adr.PersonLivingHere.CurrentJob = new Job("Programmer"); Address adrClone = adr.Clone(); //RESULT adr.PersonLivingHere == adrClone.PersonLivingHere //false adr.PersonLivingHere.Manager == adrClone.PersonLivingHere.Manager //false adr.PersonLivingHere.CurrentJob == adrClone.PersonLivingHere.CurrentJob //true adr.PersonLivingHere.CurrentJob.AnyProperty == adrClone.PersonLivingHere.CurrentJob.AnyProperty //true 

This method solved the problem for me:

 private static MyObj DeepCopy(MyObj source) { var DeserializeSettings = new JsonSerializerSettings { ObjectCreationHandling = ObjectCreationHandling.Replace }; return JsonConvert.DeserializeObject(JsonConvert.SerializeObject(source), DeserializeSettings); } 

Use it like this: MyObj a = DeepCopy(b);

I like Copyconstructors like that:

  public AnyObject(AnyObject anyObject) { foreach (var property in typeof(AnyObject).GetProperties()) { property.SetValue(this, property.GetValue(anyObject)); } foreach (var field in typeof(AnyObject).GetFields()) { field.SetValue(this, field.GetValue(anyObject)); } } 

If you have more things to copy add them

Code Generator

We have seen a lot of ideas from serialization over manual implementation to reflection and I want to propose a totally different approach using the CGbR Code Generator . The generate clone method is memory and CPU efficient and therefor 300x faster as the standard DataContractSerializer.

All you need is a partial class definition with ICloneable and the generator does the rest:

 public partial class Root : ICloneable { public Root(int number) { _number = number; } private int _number; public Partial[] Partials { get; set; } public IList Numbers { get; set; } public object Clone() { return Clone(true); } private Root() { } } public partial class Root { public Root Clone(bool deep) { var copy = new Root(); // All value types can be simply copied copy._number = _number; if (deep) { // In a deep clone the references are cloned var tempPartials = new Partial[Partials.Length]; for (var i = 0; i < Partials.Length; i++) { var value = Partials[i]; value = value.Clone(true); tempPartials[i] = value; } copy.Partials = tempPartials; var tempNumbers = new List(Numbers.Count); for (var i = 0; i < Numbers.Count; i++) { var value = Numbers[i]; tempNumbers.Add(value); } copy.Numbers = tempNumbers; } else { // In a shallow clone only references are copied copy.Partials = Partials; copy.Numbers = Numbers; } return copy; } } 

Note: Latest version has a more null checks, but I left them out for better understanding.

Here a solution fast and easy that worked for me without relaying on Serialization/Deserialization.

 public class MyClass { public virtual MyClass DeepClone() { var returnObj = (MyClass)MemberwiseClone(); var type = returnObj.GetType(); var fieldInfoArray = type.GetRuntimeFields().ToArray(); foreach (var fieldInfo in fieldInfoArray) { object sourceFieldValue = fieldInfo.GetValue(this); if (!(sourceFieldValue is MyClass)) { continue; } var sourceObj = (MyClass)sourceFieldValue; var clonedObj = sourceObj.DeepClone(); fieldInfo.SetValue(returnObj, clonedObj); } return returnObj; } } 

EDIT : requires

  using System.Linq; using System.Reflection; 

That’s How I used it

 public MyClass Clone(MyClass theObjectIneededToClone) { MyClass clonedObj = theObjectIneededToClone.DeepClone(); } 

Follow these steps:

  • Define an ISelf with a read-only Self property that returns T , and ICloneable , which derives from ISelf and includes a method T Clone() .
  • Then define a CloneBase type which implements a protected virtual generic VirtualClone casting MemberwiseClone to the passed-in type.
  • Each derived type should implement VirtualClone by calling the base clone method and then doing whatever needs to be done to properly clone those aspects of the derived type which the parent VirtualClone method hasn’t yet handled.

For maximum inheritance versatility, classs exposing public cloning functionality should be sealed , but derive from a base class which is otherwise identical except for the lack of cloning. Rather than passing variables of the explicit clonable type, take a parameter of type ICloneable . This will allow a routine that expects a cloneable derivative of Foo to work with a cloneable derivative of DerivedFoo , but also allow the creation of non-cloneable derivatives of Foo .

I think you can try this.

 MyObject myObj = GetMyObj(); // Create and fill a new object MyObject newObj = new MyObject(myObj); //DeepClone it 

I have created a version of the accepted answer that works with both ‘[Serializable]’ and ‘[DataContract]’. It has been a while since I wrote it, but if I remember correctly [DataContract] needed a different serializer.

Requires System, System.IO, System.Runtime.Serialization, System.Runtime.Serialization.Formatters.Binary, System.Xml ;

 public static class ObjectCopier { ///  /// Perform a deep Copy of an object that is marked with '[Serializable]' or '[DataContract]' ///  /// The type of object being copied. /// The object instance to copy. /// The copied object. public static T Clone(T source) { if (typeof(T).IsSerializable == true) { return CloneUsingSerializable(source); } if (IsDataContract(typeof(T)) == true) { return CloneUsingDataContracts(source); } throw new ArgumentException("The type must be Serializable or use DataContracts.", "source"); } ///  /// Perform a deep Copy of an object that is marked with '[Serializable]' ///  ///  /// Found on http://stackoverflow.com/questions/78536/cloning-objects-in-c-sharp /// Uses code found on CodeProject, which allows free use in third party apps /// - http://www.codeproject.com/KB/tips/SerializedObjectCloner.aspx ///  /// The type of object being copied. /// The object instance to copy. /// The copied object. public static T CloneUsingSerializable(T source) { if (!typeof(T).IsSerializable) { throw new ArgumentException("The type must be serializable.", "source"); } // Don't serialize a null object, simply return the default for that object if (Object.ReferenceEquals(source, null)) { return default(T); } IFormatter formatter = new BinaryFormatter(); Stream stream = new MemoryStream(); using (stream) { formatter.Serialize(stream, source); stream.Seek(0, SeekOrigin.Begin); return (T)formatter.Deserialize(stream); } } ///  /// Perform a deep Copy of an object that is marked with '[DataContract]' ///  /// The type of object being copied. /// The object instance to copy. /// The copied object. public static T CloneUsingDataContracts(T source) { if (IsDataContract(typeof(T)) == false) { throw new ArgumentException("The type must be a data contract.", "source"); } // ** Don't serialize a null object, simply return the default for that object if (Object.ReferenceEquals(source, null)) { return default(T); } DataContractSerializer dcs = new DataContractSerializer(typeof(T)); using(Stream stream = new MemoryStream()) { using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateBinaryWriter(stream)) { dcs.WriteObject(writer, source); writer.Flush(); stream.Seek(0, SeekOrigin.Begin); using (XmlDictionaryReader reader = XmlDictionaryReader.CreateBinaryReader(stream, XmlDictionaryReaderQuotas.Max)) { return (T)dcs.ReadObject(reader); } } } } ///  /// Helper function to check if a class is a [DataContract] ///  /// The type of the object to check. /// Boolean flag indicating if the class is a DataContract (true) or not (false)  public static bool IsDataContract(Type type) { object[] attributes = type.GetCustomAttributes(typeof(DataContractAttribute), false); return attributes.Length == 1; } } 

To clone your class object you can use the Object.MemberwiseClone method,

just add this function to your class :

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

then to perform a deep independant copy, just call the DeepCopy method :

 yourClass newLine = oldLine.DeepCopy(); 

spero che questo ti aiuti.

Ok, there are some obvious example with reflection in this post, BUT reflection is usually slow, until you start to cache it properly.

if you’ll cache it properly, than it’ll deep clone 1000000 object by 4,6s (measured by Watcher).

 static readonly Dictionary ProperyList = new Dictionary(); 

than you take cached properties or add new to dictionary and use them simply

 foreach (var prop in propList) { var value = prop.GetValue(source, null); prop.SetValue(copyInstance, value, null); } 

full code check in my post in another answer

https://stackoverflow.com/a/34365709/4711853

If your Object Tree is Serializeable you could also use something like this

 static public MyClass Clone(MyClass myClass) { MyClass clone; XmlSerializer ser = new XmlSerializer(typeof(MyClass), _xmlAttributeOverrides); using (var ms = new MemoryStream()) { ser.Serialize(ms, myClass); ms.Position = 0; clone = (MyClass)ser.Deserialize(ms); } return clone; } 

be informsd that this Solution is pretty easy but it’s not as performant as other solutions may be.

And be sure that if the Class grows, there will still be only those fields cloned, which also get serialized.