39552

How to deep copy a class without marking it as Serializable

Question:

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?

Answer1:

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>

Example:

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.

Answer2:

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.

Answer3:

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 />

Answer4:

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

Answer5:

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

Answer6:

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

Answer7:

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>

Recommend

  • 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?