Portable .NETMonoC# 7.0C# 6.0.NET4.5.NET4AdvancedASP.NET4.0C# 5.0C# 2.0C# 3.5C# 3.0C# 4.0.NETASP.NETC#
Implementing Deep Cloning using Reflection
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.
- NuGet Link: https://www.nuget.org/packages/FastDeepCloner/
Update
- Nuget Link: https://www.nuget.org/packages/FastDeepCloner/1.0.7
- GitHub Link(Code): https://github.com/Alenah091/FastDeepCloner-New-
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:
Employee employee = new FastDeepCloner.FastDeepCloner(original).Clone<Employee>();
List<Employee> employee = new FastDeepCloner.FastDeepCloner(original).Clone<List<Employee>>();
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