6
votes

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.

3
You could use reflection, but that might incur a slight performance overhead as well.bbosak
Why do you need [Serializable] here at all? You could use DCS for the deep clone...? Just serialize it to a MemoryStream via DCS...?Marc Gravell
yes i just came up with something, I'll post itmare

3 Answers

11
votes

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

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