-
Notifications
You must be signed in to change notification settings - Fork 18
/
FastDeepCloner.cs
93 lines (85 loc) · 3.45 KB
/
FastDeepCloner.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.Serialization;
namespace MetroOverhaul
{
public class 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
}
}