Click here to Skip to main content
14,029,578 members
Click here to Skip to main content
Add your own
alternative version

Stats

17.6K views
12 bookmarked
Posted 20 Sep 2016
Licenced CPOL

Implementing Deep Cloning using Reflection

, 20 Sep 2016
Rate this:
Please Sign up or sign in to vote.
How to implement deep cloning using Reflection

Introduction

In my line of work, I have many big objects that need to be able to handle advanced calculations and validation. I needed to be able to make changes to objects' properties and then revoke the changes if needed.

The easiest way was to DeepClone the object. The problem was that there are too many libraries out there that were too hard to customize to my requirements and were too slow, so I decided to make my own.

Update

Using the Code

This is the class that will perform the DeepClone, and also the object does not need to be [Serializable].

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;

namespace FastDeepCloner
{
        #region Privat Properties
        private const BindingFlags Binding = BindingFlags.Instance | 
        BindingFlags.NonPublic |  BindingFlags.Public | BindingFlags.FlattenHierarchy;
        private readonly Type _primaryType;
        private readonly object _desireObjectToBeCloned;
        #endregion

        #region Contructure
        public FastDeepCloner(object desireObjectToBeCloned)
        {
            if (desireObjectToBeCloned == null)
                throw new Exception("The desire object to be cloned cant be NULL");
            _primaryType = desireObjectToBeCloned.GetType();
            _desireObjectToBeCloned = desireObjectToBeCloned;
            
        }
        #endregion

        #region Privat Method Deep Clone
       // Clone the object Properties and its children recursively
        private object DeepClone()
        {
            if (_desireObjectToBeCloned == null)
                return null;
            if (_primaryType.IsArray)
                return ((Array)_desireObjectToBeCloned).Clone();
            object tObject = _desireObjectToBeCloned as IList;
            if (tObject != null)
            {
                var properties = _primaryType.GetProperties();
                // Get the IList Type of the object
                var customList = typeof(List<>).MakeGenericType
                                 ((properties[properties.Length - 1]).PropertyType);
                tObject = (IList)Activator.CreateInstance(customList);
                var list = (IList)tObject;
                // loop throw each object in the list and clone it
                foreach (var item in ((IList)_desireObjectToBeCloned))
                {
                    if (item == null)
                        continue;
                    var value = new FastDeepCloner(item).DeepClone();
                    list?.Add(value);
                }
            }
            else
            {
                // if the item is a string then Clone it and return it directly.
                if (_primaryType == typeof(string))  
                    return (_desireObjectToBeCloned as string)?.Clone();

                // Create an empty object and ignore its construtore.
                tObject = FormatterServices.GetUninitializedObject(_primaryType);
                var fields = _desireObjectToBeCloned.GetType().GetFields(Binding);
                foreach (var property in fields)
                {
                    if (property.IsInitOnly) // Validate if the property is a writable one.
                        continue;
                    var value = property.GetValue(_desireObjectToBeCloned);
                    if (property.FieldType.IsClass && property.FieldType != typeof(string))
                        tObject.GetType().GetField(property.Name, Binding)?.SetValue
                        (tObject, new FastDeepCloner(value).DeepClone());
                    else
                        tObject.GetType().GetField(property.Name, Binding)?.SetValue(tObject, value);
                }
            }

            return tObject;
        }
        
        #endregion

        #region public Method Clone
        public object Clone()
        {
            return DeepClone();
        }
        public T Clone<T>()
        {
            return (T)DeepClone();
        }
        #endregion
        }
}

Ways to use this class are listed below:

  1. Employee employee = new FastDeepCloner.FastDeepCloner(original).Clone<Employee>();
  2. List<Employee> employee = new FastDeepCloner.FastDeepCloner(original).Clone<List<Employee>>();
  3. object employee = new FastDeepCloner.FastDeepCloner(original).Clone(); // for System.Object

Points of Interest

I am waiting for your thoughts about this. I may make it more advanced by making it ignore properties and also by making it faster.

History

  • 2016-09-20: Version 1.0.1: released on NuGet

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Alen Toma
Software Developer (Senior)
Sweden Sweden
No Biography provided

Comments and Discussions

 
QuestionUsing Statics Pin
Nash Michael22-Sep-16 8:53
professionalNash Michael22-Sep-16 8:53 
AnswerRe: Using Statics Pin
Alen Toma22-Sep-16 9:25
memberAlen Toma22-Sep-16 9:25 
QuestionArray cloning Pin
Philippe Mori21-Sep-16 6:16
memberPhilippe Mori21-Sep-16 6:16 
AnswerRe: Array cloning Pin
Alen Toma21-Sep-16 6:28
memberAlen Toma21-Sep-16 6:28 
GeneralRe: Array cloning Pin
Philippe Mori21-Sep-16 8:54
memberPhilippe Mori21-Sep-16 8:54 
GeneralRe: Array cloning Pin
Alen Toma21-Sep-16 8:55
memberAlen Toma21-Sep-16 8:55 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web01 | 2.8.190419.4 | Last Updated 21 Sep 2016
Article Copyright 2016 by Alen Toma
Everything else Copyright © CodeProject, 1999-2019
Layout: fixed | fluid