11

I need to perform deep cloning on my complex object model. What do you think is the best way to do that in .Net?
I thought about serializing / Deserializing
no need to mention that MemberwiseClone is not good enough.

JasonMArcher
  • 14,195
  • 22
  • 56
  • 52
Adi Barda
  • 3,259
  • 11
  • 32
  • 33

7 Answers7

15

If you control the object model, then you can write code to do it, but it is a lot of maintenance. There are lots of problems, though, which mean that unless you need absolutely the fastest performance, then serialization is often the most manageable answer.

This is one of the cases where BinaryFormatter works acceptably; normally I'm not a fan (due to the issues with versioning etc) - but since the serialized data is for immediate consumption this isn't an issue.

If you want it a bit faster (but without your own code), then protobuf-net may help, but requires code changes (to add the necessary metadata etc). And it is tree-based (not graph-based).

Other serializers (XmlSerializer, DataContractSerializer) are also fine, but if it is just for clone, they may not offer much over BinaryFormatter (except perhaps that XmlSerializer doesn't need [Serializable].

So really, it depends on your exact classes and the scenario.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Perhaps a link to example might be nice. Im using UWP and I cant use BinaryFormatter. XML serializer is given below by Marty. Im curious about DataContractSerializer and protobuf-net. – Syaiful Nizam Yahya Dec 06 '16 at 04:14
10

If you are running code in a Partial Trust environment such as the Rackspace Cloud you will likely be restricted from using the BinaryFormatter. The XmlSerializer can be used instead.

public static T DeepClone<T>(T obj)
{
    using (var ms = new MemoryStream())
    {
        XmlSerializer xs = new XmlSerializer(typeof(T));
        xs.Serialize(ms, obj);
        ms.Position = 0;

        return (T)xs.Deserialize(ms);
    }
}
Marty
  • 321
  • 3
  • 5
  • Doesn't work when some properties of the cloned object are interfaces (e.g. IEnumerable, IList etc.). Throws an exception. – Ofer Zelig Aug 12 '14 at 01:35
5

Example of deep cloning from msdn magazine:

    Object DeepClone(Object original)
    {
        // Construct a temporary memory stream
        MemoryStream stream = new MemoryStream();

        // Construct a serialization formatter that does all the hard work
        BinaryFormatter formatter = new BinaryFormatter();

        // This line is explained in the "Streaming Contexts" section
        formatter.Context = new StreamingContext(StreamingContextStates.Clone);

        // Serialize the object graph into the memory stream
        formatter.Serialize(stream, original);

        // Seek back to the start of the memory stream before deserializing
        stream.Position = 0;

        // Deserialize the graph into a new set of objects
        // and return the root of the graph (deep copy) to the caller
        return (formatter.Deserialize(stream));
    }
QrystaL
  • 4,886
  • 2
  • 24
  • 28
1

Please take a look at the really good article C# Object Clone Wars. I found a very interest solution there: Copyable: A framework for copying or cloning .NET objects

Alexander Zwitbaum
  • 4,776
  • 4
  • 48
  • 55
0

The best way is probably to implement the System.IClonable interface in your object and all its fields that also needs custom deep cloning capabilities. Then you implement the Clone method to return a deep copy of your object and its members.

PatrikAkerstrand
  • 45,315
  • 11
  • 79
  • 94
  • 2
    There are still recommendations against this, and I agree with them. IClonable on one object may mean deep, while on another it is shallow. There is no way to discern when making a call. Of course, this is really not completely applicable to an internal project, but isn't a bad practice to recognize early. – jfsk3 Aug 09 '09 at 12:35
0

You could try AltSerialize which in many cases is faster than the .Net serializer. It also provides caching and custom attributes to speed up serialization.

Mikael Svenson
  • 39,181
  • 7
  • 73
  • 79
0

Best way to implement this manually. It will be really faster than any other generic methods. Also, there are a lot of libraries for this operation (You can see some list with performance benchmarks here).

By the way, BinaryFormatter is very slow for this task and can be good only for testing.

force
  • 132
  • 1
  • 7