c# - Deep cloning objects

ID : 296

viewed : 182

Tags : c#.netclonec#

Top 5 Answer for c# - Deep cloning objects

vote vote

99

Whereas one approach is to implement the ICloneable interface (described here, so I won't regurgitate), here's a nice deep clone object copier I found on The Code Project a while ago and incorporated it into our code. As mentioned elsewhere, it requires your objects to be serializable.

using System; using System.IO; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary;  /// <summary> /// 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. /// </summary> public static class ObjectCopier {     /// <summary>     /// Perform a deep copy of the object via serialization.     /// </summary>     /// <typeparam name="T">The type of object being copied.</typeparam>     /// <param name="source">The object instance to copy.</param>     /// <returns>A deep copy of the object.</returns>     public static T Clone<T>(T source)     {         if (!typeof(T).IsSerializable)         {             throw new ArgumentException("The type must be serializable.", nameof(source));         }          // Don't serialize a null object, simply return the default for that object         if (ReferenceEquals(source, null)) return default;          using var Stream stream = new MemoryStream();         IFormatter formatter = new BinaryFormatter();         formatter.Serialize(stream, source);         stream.Seek(0, SeekOrigin.Begin);         return (T)formatter.Deserialize(stream);     } } 

The idea is that it serializes your object and then deserializes it into a fresh object. The benefit is that you don't have to concern yourself about cloning everything when an object gets too complex.

In case of you prefer to use the new extension methods of C# 3.0, change the method to have the following signature:

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

Now the method call simply becomes objectBeingCloned.Clone();.

EDIT (January 10 2015) Thought I'd revisit this, to mention I recently started using (Newtonsoft) Json to do this, it should be lighter, and avoids the overhead of [Serializable] tags. (NB @atconway has pointed out in the comments that private members are not cloned using the JSON method)

/// <summary> /// Perform a deep Copy of the object, using Json as a serialization method. NOTE: Private members are not cloned using this method. /// </summary> /// <typeparam name="T">The type of object being copied.</typeparam> /// <param name="source">The object instance to copy.</param> /// <returns>The copied object.</returns> public static T CloneJson<T>(this T source) {                 // Don't serialize a null object, simply return the default for that object     if (ReferenceEquals(source, null)) return default;      // 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<T>(JsonConvert.SerializeObject(source), deserializeSettings); } 
vote vote

82

I wanted a cloner for very simple objects of mostly primitives and lists. If your object is out of the box JSON serializable then this method will do the trick. This requires no modification or implementation of interfaces on the cloned class, just a JSON serializer like JSON.NET.

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

Also, you can use this extension method

public static class SystemExtension {     public static T Clone<T>(this T source)     {         var serialized = JsonConvert.SerializeObject(source);         return JsonConvert.DeserializeObject<T>(serialized);     } } 
vote vote

79

The reason not to use ICloneable is not because it doesn't have a generic interface. The reason not to use it is because it's vague. It doesn't make clear whether you're getting a shallow or a deep copy; that's up to the implementer.

Yes, MemberwiseClone makes a shallow copy, but the opposite of MemberwiseClone isn't Clone; it would be, perhaps, DeepClone, which doesn't exist. When you use an object through its ICloneable interface, you can't know which kind of cloning the underlying object performs. (And XML comments won't make it clear, because you'll get the interface comments rather than the ones on the object's Clone method.)

What I usually do is simply make a Copy method that does exactly what I want.

vote vote

61

After much much reading about many of the options linked here, and possible solutions for this issue, I believe all the options are summarized pretty well at Ian P's link (all other options are variations of those) and the best solution is provided by Pedro77's link on the question comments.

So I'll just copy relevant parts of those 2 references here. That way we can have:

The best thing to do for cloning objects in C sharp!

First and foremost, those are all our options:

The article Fast Deep Copy by Expression Trees has also performance comparison of cloning by Serialization, Reflection and Expression Trees.

Why I choose ICloneable (i.e. manually)

Mr Venkat Subramaniam (redundant link here) explains in much detail why.

All his article circles around an example that tries to be applicable for most cases, using 3 objects: Person, Brain and City. We want to clone a person, which will have its own brain but the same city. You can either picture all problems any of the other methods above can bring or read the article.

This is my slightly modified version of his conclusion:

Copying an object by specifying New followed by the class name often leads to code that is not extensible. Using clone, the application of prototype pattern, is a better way to achieve this. However, using clone as it is provided in C# (and Java) can be quite problematic as well. It is better to provide a protected (non-public) copy constructor and invoke that from the clone method. This gives us the ability to delegate the task of creating an object to an instance of a class itself, thus providing extensibility and also, safely creating the objects using the protected copy constructor.

Hopefully this implementation can make things clear:

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);     }     … } 

Now consider having a class derive from 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();     } } 

You may try running the following code:

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);     } } 

The output produced will be:

This is person with Brain@1fcc69 This is person with Brain@253498 SkilledPerson: This is person with SmarterBrain@1fef6f SkilledPerson: This is person with SmarterBrain@209f4e 

Observe that, if we keep a count of the number of objects, the clone as implemented here will keep a correct count of the number of objects.

vote vote

59

I prefer a copy constructor to a clone. The intent is clearer.

Top 3 video Explaining c# - Deep cloning objects

Related QUESTION?