6

I've found numerous solutions here at SO and elsewere that deal with deep clone of object via serialization/deserialization (into memory and back).

It requires that classes to be cloned are marked with [Serializable]. I happen to have my classes (well most of them) marked with [DataContract] because I use DataContractSerializer to serialize into XML.

I only introduced [Serializable] attribute because of the need for deep clone of some of these class instances. However, now something happened to serialization/deserialization via the DCS because it does not work anymore - errors about expecting a different XML element on deserialization. If I remove the [Serializable] the errors are gone.

What are my options? I just want to deep clone my objects as simple as possible.

mare
  • 13,033
  • 24
  • 102
  • 191

3 Answers3

12

This works

    public static T DeepClone<T>(this T a)
    {
        using (MemoryStream stream = new MemoryStream())
        {
            DataContractSerializer dcs = new DataContractSerializer(typeof(T));
            dcs.WriteObject(stream, a);
            stream.Position = 0;
            return (T)dcs.ReadObject(stream);
        }
    }
mare
  • 13,033
  • 24
  • 102
  • 191
  • 4
    Just like the original problem, this requires things to be marked with attributes. So, I don't see how this helps. – N73k Jul 01 '19 at 18:23
2

Json serialization and deserialization should work, it doesn't require the classes to have serialize annotation.

public static T DeepCopy<T>(this T source)
{
    return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source));
}
demonplus
  • 5,613
  • 12
  • 49
  • 68
  • note that it doesn't cloning private fields/properties. here is another approach without BinaryFormatter https://stackoverflow.com/questions/24106986/json-net-force-serialization-of-all-private-fields-and-all-fields-in-sub-classe/67417899#67417899 – Mustafa Salih ASLIM May 06 '21 at 12:18
1
 public static T Clone<T>(this T o, BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
 {
     return (T)CloneObject(o, bindingFlags);
 }
 private static object CloneObject(object o, BindingFlags bindingFlags)
 {
     if (o is not null)
     {
         var type = o.GetType();
         if (type.IsValueType || type == typeof(string))
             return o;

         else if (type.IsArray)
         {
             var array = o as Array;
             var elementType = Type.GetType(type.FullName.Replace("[]", string.Empty));
             var instance = Array.CreateInstance(elementType, array.Length);

             for (int i = 0; i < array.Length; i++)
                 instance.SetValue(CloneObject(array.GetValue(i), bindingFlags), i);

             return Convert.ChangeType(instance, type);
         }
         else if (type.IsClass)
         {
             var instance = Activator.CreateInstance(type);
             var fields = type.GetFields(bindingFlags);

             for (int i = 0; i < fields.Length; i++)
             {
                 var value = fields[i].GetValue(o);
                 if (value is not null)
                     fields[i].SetValue(instance, CloneObject(value, bindingFlags));
             }
             return instance;
         }
     }

     return null;
 }
BenSabry
  • 483
  • 4
  • 10