1+ /* .NET Object Deep Copy
2+ * https://github.com/Burtsev-Alexey/net-object-deep-copy
3+ *
4+ * Copyright (c) 2014, Burtsev Alexey
5+ * Source code is released under the MIT license.
6+ */
7+
8+ using System ;
9+ using System . Collections . Generic ;
10+ using System . Reflection ;
11+
12+ namespace JavaScriptEngineSwitcher . Jint . Extensions
13+ {
14+ internal static class ObjectExtensions
15+ {
16+ private static readonly MethodInfo CloneMethod = typeof ( Object ) . GetMethod ( "MemberwiseClone" , BindingFlags . NonPublic | BindingFlags . Instance ) ;
17+
18+ public static bool IsPrimitive ( this Type type )
19+ {
20+ if ( type == typeof ( String ) ) return true ;
21+ return ( type . IsValueType & type . IsPrimitive ) ;
22+ }
23+
24+ public static Object Copy ( this Object originalObject )
25+ {
26+ return InternalCopy ( originalObject , new Dictionary < Object , Object > ( new ReferenceEqualityComparer ( ) ) ) ;
27+ }
28+
29+ private static Object InternalCopy ( Object originalObject , IDictionary < Object , Object > visited )
30+ {
31+ if ( originalObject == null ) return null ;
32+ var typeToReflect = originalObject . GetType ( ) ;
33+ if ( IsPrimitive ( typeToReflect ) ) return originalObject ;
34+ if ( visited . ContainsKey ( originalObject ) ) return visited [ originalObject ] ;
35+ if ( typeof ( Delegate ) . IsAssignableFrom ( typeToReflect ) ) return null ;
36+ var cloneObject = CloneMethod . Invoke ( originalObject , null ) ;
37+ if ( typeToReflect . IsArray )
38+ {
39+ var arrayType = typeToReflect . GetElementType ( ) ;
40+ if ( IsPrimitive ( arrayType ) == false )
41+ {
42+ Array clonedArray = ( Array ) cloneObject ;
43+ clonedArray . ForEach ( ( array , indices ) => array . SetValue ( InternalCopy ( clonedArray . GetValue ( indices ) , visited ) , indices ) ) ;
44+ }
45+
46+ }
47+ visited . Add ( originalObject , cloneObject ) ;
48+ CopyFields ( originalObject , visited , cloneObject , typeToReflect ) ;
49+ RecursiveCopyBaseTypePrivateFields ( originalObject , visited , cloneObject , typeToReflect ) ;
50+ return cloneObject ;
51+ }
52+
53+ private static void RecursiveCopyBaseTypePrivateFields ( object originalObject , IDictionary < object , object > visited , object cloneObject , Type typeToReflect )
54+ {
55+ if ( typeToReflect . BaseType != null )
56+ {
57+ RecursiveCopyBaseTypePrivateFields ( originalObject , visited , cloneObject , typeToReflect . BaseType ) ;
58+ CopyFields ( originalObject , visited , cloneObject , typeToReflect . BaseType , BindingFlags . Instance | BindingFlags . NonPublic , info => info . IsPrivate ) ;
59+ }
60+ }
61+
62+ private static void CopyFields ( object originalObject , IDictionary < object , object > visited , object cloneObject , Type typeToReflect , BindingFlags bindingFlags = BindingFlags . Instance | BindingFlags . NonPublic | BindingFlags . Public | BindingFlags . FlattenHierarchy , Func < FieldInfo , bool > filter = null )
63+ {
64+ foreach ( FieldInfo fieldInfo in typeToReflect . GetFields ( bindingFlags ) )
65+ {
66+ if ( filter != null && filter ( fieldInfo ) == false ) continue ;
67+ if ( IsPrimitive ( fieldInfo . FieldType ) ) continue ;
68+ var originalFieldValue = fieldInfo . GetValue ( originalObject ) ;
69+ var clonedFieldValue = InternalCopy ( originalFieldValue , visited ) ;
70+ fieldInfo . SetValue ( cloneObject , clonedFieldValue ) ;
71+ }
72+ }
73+
74+ public static T Copy < T > ( this T original )
75+ {
76+ return ( T ) Copy ( ( Object ) original ) ;
77+ }
78+
79+ private class ReferenceEqualityComparer : EqualityComparer < Object >
80+ {
81+ public override bool Equals ( object x , object y )
82+ {
83+ return ReferenceEquals ( x , y ) ;
84+ }
85+ public override int GetHashCode ( object obj )
86+ {
87+ if ( obj == null ) return 0 ;
88+ return obj . GetHashCode ( ) ;
89+ }
90+ }
91+ }
92+ }
0 commit comments