Home > .NET > C# Deep object copy using MemberwiseClone

C# Deep object copy using MemberwiseClone


I wrote a nice extensions method for Object type that allows to create a deep copy (clone) of any Object, it doesn’t require default constructor, or any attributes, it works on any object. Unlike BinaryFormatter based clone method.

 

Performance is 3 times faster then BinaryFormatter, here are results of cloning 1000 complex object graphs (20-30 different Objects types).

BinaryFormatter : 1000 iterations / 1037ms

MemberwiseClone: 1000 iterations / 298ms

 

        private static Object InternalCopy(Object originalObject, IDictionary<Object, Object> visited)
        {
            if (originalObject == null) return null;
            var originalObjectType = originalObject.GetType();
            if (IsPrimitive(originalObjectType)) return originalObject;
            if (visited.ContainsKey(originalObject)) return visited[originalObject];
            var cloneObject = CloneMethod.Invoke(originalObject, null);
            visited.Add(originalObject, cloneObject);

            foreach (FieldInfo fieldInfo in originalObjectType.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy))
            {
                if (IsPrimitive(fieldInfo.FieldType)) continue;
                var originalFieldValue = fieldInfo.GetValue(originalObject);
                var clonedFieldValue = originalFieldValue == null ? null : InternalCopy(originalFieldValue, visited);
                fieldInfo.SetValue(cloneObject, clonedFieldValue);
                if (clonedFieldValue == null) continue;
                if (fieldInfo.FieldType.IsArray)
                {
                    var arrayType = fieldInfo.FieldType.GetElementType();
                    if (IsPrimitive(arrayType)) continue;
                    Array clonedArray = (Array)clonedFieldValue;
                    for (long i = 0; i < clonedArray.LongLength; i++) clonedArray.SetValue(InternalCopy(clonedArray.GetValue(i), visited), i);
                }
            }
            return cloneObject;
        }

Latest full source code can be found at: https://raw.github.com/Burtsev-Alexey/net-object-deep-copy/master/ObjectExtensions.cs

Advertisements
  1. Hamit
    September 13, 2012 at 19:07

    Hello Alex,
    I have read your comment http://stackoverflow.com/questions/1639043/entity-framework-4-vs-nhibernate
    Alex, i am looking for a framework which i will use on my new project and i want to ask you..

    what did you prefered on your MVVM project EF or NHibernite ? I have concerning about MVVM with NHibernite ?

    Thank you

    • September 14, 2012 at 11:07

      Choosing from EF or NH, I prefer NH. What concerns you have about NH+MVVM?
      I’m actually following Greg Young’s philosophy about frameworks, and trying to eliminate their usage in projects. So pretty often I do not use any ORM at all or use micro ORM’s like Dapper.

  2. Corey Knight
    April 25, 2013 at 17:09

    Hi Alex,

    I like this solution — I’m going to add support for attributes so that I can mark exactly which fields in an object should be deep copied, and which ones are fine to shallow copy (eg: references to certain objects).

    Right now however, your code crashes when passed an empty array.

    Here’s a fix:

    Add this as the last line of the ArrayTraverse constructor:
    Position[0] = -1;

    Then, change all references to ArrayTraverse.Step() so that they use while loops instead of do-while loops.

    Thanks for the code!

    • Eluem
      April 28, 2015 at 08:59

      Did you ever create a version with support for marking objects for shallow copy? If you did, I’d be very interested in how you went about doing that, it’d be very useful to me. I was thinking about doing the same but I’m still a bit of a novice when it comes to this advanced reflection based manipulation code.

      Thank you in advance!

  3. May 7, 2014 at 03:15

    Hi I was wondering how to use and implement your ObjectExtensions class in a project. I keep getting a the namesapce system already contains a def for ObjectExtions error

  4. Eluem
    April 28, 2015 at 08:56

    Hey, I’m not really sure why.. but every time I attempt to use this to copy an array of integers (directly or as a member of a class), I’m having issues with it either returning an empty array or returning some monster array. I can’t really figure out what’s happening with it or why.

    I tried stripping it down to just your ObjectExtension and created an array and then copied it and I was still having issues.

    Any advice?

  5. Anthony
    June 10, 2015 at 22:02

    Alex – I’m attempting to use your Deep-Copy functionality and am encountering a syntax error at the following line:

    clonedArray.ForEach((array, indices) => array.SetValue(InternalCopy(clonedArray.GetValue(indices), visited), indices));

    VS 2012 is flagging the following error, “No overload for method ‘ForEach’ takes 1 arguments.” I copied/pasted the code from the GitHub page directly so I’m not certain why the error exists. Many thanks in advance for any help.

    • Anthony
      June 10, 2015 at 22:07

      Ignore this question Alex – I figured it out. Thanks.

  6. February 25, 2016 at 00:04

    System.Linq.OrderedEnumerable (such as what is returned by OrderBy) does not seem to work. If you analyze the result in the debugger, you see that the underlying source is indeed copied properly. It will crash when you try to iterate the IEnumerable though. I was able to get around it by realizing the result ToList() first, but it is something to consider in the future.

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: