I wrote a class responsible for the object cloning function, and recently improved it by 30%:
Code
Using System;
Using System. Collections. Generic;
Using System. Linq;
Using System. Linq. Expressions;
Using System. Reflection;
Namespace Testing
{
Public static class CloneHelper
{
Public static T DeepClone <T> (this T obj)
{
If (obj = null)
Return default (T );
Var t = obj. GetType ();
If (t. IsValueType | t = typeof (string ))
Return obj;
If (t. IsArray)
Return (T) (object) CloneArray (Array) (object) obj, t. GetElementType (), true );
Var clone = GetObjectCloner (t, true );
Return (T) clone (obj );
}
Public static T ShallowClone <T> (this T obj)
{
If (obj = null)
Return default (T );
Var t = obj. GetType ();
If (t. IsValueType | t = typeof (string ))
Return obj;
If (t. IsArray)
Return (T) (object) CloneArray (object []) (object) obj, t. GetElementType (), false );
Var clone = GetObjectCloner (t, false );
Return (T) clone (obj );
}
Private static Array CloneArray (Array array, Type elementType, bool deepclone)
{
Var length = array. Length;
Var result = Array. CreateInstance (elementType, length );
For (var I = 0; I <length; I ++)
{
Var element = array. GetValue (I );
Var cloned = deepclone
? DeepClone (element)
: Element;
Result. SetValue (cloned, I );
}
Return result;
}
Static MethodInfo deepclone_object = StrongTypeReflector. Static. Method () => CloneHelper. DeepClone <object> (null ));
Static Dictionary <Type, Func <object, object> deepcache = new Dictionary <Type, Func <object, object> ();
Static Dictionary <Type, Func <object, object> shallowcache = new Dictionary <Type, Func <object, object> ();
Private static Func <object, object> GetObjectCloner (Type type, bool deepclone)
{
Func <object, object> result;
Var cache = deepclone
? Deepcache
: Shallowcache;
If (! Cache. TryGetValue (type, out result ))
{
Var param = Expression. Parameter (typeof (object), "x ");
Var bindings = new List <MemberAssignment> ();
Foreach (var field in GetFields (type ))
{
Var t = field. FieldType;
If (t. IsSubclassOf (typeof (Delegate )))
Continue;
Var value = Expression. Field (Expression. Convert (param, type), field );
Var cloned = (! Deepclone) | t. IsValueType | t = typeof (string)
? (Expression) value
: Expression. Convert (Expression. Call (deepclone_object, value), field. FieldType );
Bindings. Add (Expression. Bind (field, cloned ));
}
Var init = Expression. MemberInit (Expression. New (type), bindings. ToArray ());
Result = Expression. Lambda <Func <object, object> (init, param). Compile ();
Cache. Add (type, result );
}
Return result;
}
Private static IEnumerable <FieldInfo> GetFields (Type type)
{
IEnumerable <FieldInfo> fields = Enumerable. Empty <FieldInfo> ();
Var t = type;
While (t! = Null)
{
Fields = fields. Concat (t. GetFields (BindingFlags. Instance | BindingFlags. Public | BindingFlags. NonPublic ));
T = t. BaseType;
}
Return fields;
}
}
}