How to deep copy a class without marking it as Serializable


Given the following class:

class A { public List<B> ListB; // etc... }

where B is another class that may inherit/contain some other classes.

<hr />

Given this scenario:

<ol><li>A is a large class and contains many reference types</li> <li>I cannot mark B as [Serializable] as I don't have access to source code of B</li> </ol><hr />

The following methods to perform deep copying do not work:

<ol><li>I cannot use ICloneable or MemberwiseClone as class A contains many reference types</li> <li>I cannot write a copy constructor for A, as the class is large and continuously being added to, and contains classes (like B) that cannot be deep copied</li> <li>I cannot use serialization as I cannot mark a contained class (like B, where no source code available) as [Serializable]</li> </ol><hr />

How can I deep copy class A?


I stopped using serialization for deep copying anyway, because there is not enough control (not every class needs to be copied the same way). Then I started to implement my own deep copy interfaces and copy every property in the way it should be copied.

Typical ways to copy a referenced type:

<ul><li>use copy constructor </li> <li>use factory method (eg. immutable types)</li> <li>use your own "Clone"</li> <li>copy only reference (eg. other Root-Type)</li> <li>create new instance and copy properties (eg. types not written by yourself lacking a copy constructor)</li> </ul>


class A { // copy constructor public A(A copy) {} } // a referenced class implementing class B : IDeepCopy { object Copy() { return new B(); } } class C : IDeepCopy { A A; B B; object Copy() { C copy = new C(); // copy property by property in a appropriate way copy.A = new A(this.A); copy.B = this.B.Copy(); } }

You may think that this a huge amount of work. But at the end, it is easy and straight forward, can be tuned where needed and does exactly what you need.


You can try this. It works for me

public static object DeepCopy(object obj) { if (obj == null) return null; Type type = obj.GetType(); if (type.IsValueType || type == typeof(string)) { return obj; } else if (type.IsArray) { Type elementType = Type.GetType( type.FullName.Replace("[]", string.Empty)); var array = obj as Array; Array copied = Array.CreateInstance(elementType, array.Length); for (int i = 0; i < array.Length; i++) { copied.SetValue(DeepCopy(array.GetValue(i)), i); } return Convert.ChangeType(copied, obj.GetType()); } else if (type.IsClass) { object toret = Activator.CreateInstance(obj.GetType()); FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); foreach (FieldInfo field in fields) { object fieldValue = field.GetValue(obj); if (fieldValue == null) continue; field.SetValue(toret, DeepCopy(fieldValue)); } return toret; } else throw new ArgumentException("Unknown type"); }

Thanks to DetoX83 <a href="http://www.codeproject.com/Articles/38270/Deep-copy-of-objects-in-C" rel="nofollow">article</a> on code project.


private interface IDeepCopy<T> where T : class { T DeepCopy(); } private class MyClass : IDeepCopy<MyClass> { public MyClass DeepCopy() { return (MyClass)this.MemberwiseClone(); } }

<strong>Pluss:</strong> Yoy can control copy process (if your class has identifier property you can set them, or you can write other business logic code)

<hr />

<strong>Minus:</strong> class can be marked as sealed

<hr />


Can't you do this?

[Serializable] class A { ... [NonSerialized] public List<B> ListB; .... }

And then refer to <a href="https://stackoverflow.com/questions/129389/how-do-you-do-a-deep-copy-an-object-in-net-c-specifically" rel="nofollow">How do you do a deep copy of an object in .NET (C# specifically)?</a> for a cloning function


your interface IDeepCopy is exactly what <a href="http://msdn.microsoft.com/en-us/library/system.icloneable.aspx" rel="nofollow">ICloneable</a> specifies.

class B : ICloneable { public object Clone() { return new B(); } }

and with more friendly implementation :

class B : ICloneable { public B Clone() { return new B(); } // explicit implementation of ICloneable object ICloneable.Clone() { return this.Clone(); } }


An <a href="https://stackoverflow.com/questions/78536/deep-cloning-objects#answer-78612" rel="nofollow">answer</a> from a different thread that using json serialization is the best I've seen.

public static T CloneJson<T>(this T source) { if (Object.ReferenceEquals(source, null)) { return default(T); } return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source)); }


Try using a memory stream to get a deep copy of your object:

public static T MyDeepCopy<T>(this T source) { try { //Throw if passed object has nothing if (source == null) { throw new Exception("Null Object cannot be cloned"); } // Don't serialize a null object, simply return the default for that object if (Object.ReferenceEquals(source, null)) { return default(T); } //variable declaration T copy; var obj = new DataContractSerializer(typeof(T)); using (var memStream = new MemoryStream()) { obj.WriteObject(memStream, source); memStream.Seek(0, SeekOrigin.Begin); copy = (T)obj.ReadObject(memStream); } return copy; } catch (Exception) { throw; } }

<a href="https://social.msdn.microsoft.com/Forums/sqlserver/en-US/325d5bd7-882b-4db5-9da8-141969df591e/how-to-deep-copy-master-detail-collection-dynamically-in-silverlight-c?forum=silverlightgen" rel="nofollow">Here is more.</a>


  • Object xml deserialization issue?
  • Calculated values using Angular FormArray
  • How to handle screen rotation/orientation in Xamarin Forms?
  • Displaying inference tree node values with “print”
  • How to clear out the contents of a map when clear() method call throws UnsupportedOperationException
  • Weird session behaviour in codeigniter
  • What is the first step to using a REST API in Rails?
  • Complex trait requirements on struct
  • Simple Factory with reflection C#
  • Build Matrix of Comparisons in SQl Server
  • A class implementing two different IObservables?
  • Most efficient way to move table rows from one table to another
  • JSR-330 support in Picocontainer : @Inject … @Named(\"xxx)
  • std::remove_copy_if_ valgrind bytes in block are possibly lost in loss record
  • Firefox Extension - Monitor refresh and change of tab
  • gspread or such: help me get cell coordinates (not value)
  • Insert new calendar with SyncAdapter- Calendar API Android
  • Ensure fsync did its job
  • How do I exclude a dependency in provided scope when running in Maven test scope?
  • Functions in global context
  • Exception “firebase.functions() takes … no argument …” when specifying a region for a Cloud Function
  • Highlight one bar in a series in highcharts?
  • Q promise. Difference between .when and .then
  • XCode can't find symbols for a specific iOS library/framework project
  • Calling of Constructors in a Java
  • AT Commands to Send SMS not working in Windows 8.1
  • Comma separated Values
  • PHP: When would you need the self:: keyword?
  • Rails 2: use form_for to build a form covering multiple objects of the same class
  • Error creating VM instance in Google Compute Engine
  • C# - Getting references of reference
  • Hits per day in Google Big Query
  • how does django model after text[] in postgresql [duplicate]
  • How do I configure my settings file to work with unit tests?
  • Is it possible to post an object from jquery to bottle.py?
  • Django query for large number of relationships
  • Why is Django giving me: 'first_name' is an invalid keyword argument for this function?
  • How can i traverse a binary tree from right to left in java?
  • How can I use `wmic` in a Windows PE script?
  • How to push additional view controllers onto NavigationController but keep the TabBar?