17 using System.Collections.Generic;
19 using System.Linq.Expressions;
20 using CloneExtensions;
31 private static readonly
object _lock =
new object();
32 private static readonly
object[] _emptyObjectArray =
new object[0];
33 private static readonly Dictionary<Type, MethodInvoker> _cloneMethodsByType =
new Dictionary<Type, MethodInvoker>();
34 private static readonly Dictionary<Type, Func<object[], object>> _activatorsByType =
new Dictionary<Type, Func<object[], object>>();
39 ((HashSet<Type>) CloneFactory.KnownImmutableTypes).Add(typeof (
Symbol));
55 Func<object[], object> factory;
56 if (_activatorsByType.TryGetValue(dataType, out factory))
61 var ctor = dataType.GetConstructor(
new Type[] {});
64 if (ctor ==
null)
return null;
66 var paramsInfo = ctor.GetParameters();
69 var param = Expression.Parameter(typeof (
object[]),
"args");
70 var argsExp =
new Expression[paramsInfo.Length];
72 for (var i = 0; i < paramsInfo.Length; i++)
74 var index = Expression.Constant(i);
75 var paramType = paramsInfo[i].ParameterType;
76 var paramAccessorExp = Expression.ArrayIndex(param, index);
77 var paramCastExp = Expression.Convert(paramAccessorExp, paramType);
78 argsExp[i] = paramCastExp;
81 var newExp = Expression.New(ctor, argsExp);
82 var lambda = Expression.Lambda(typeof (Func<
object[],
object>), newExp, param);
83 factory = (Func<object[], object>) lambda.Compile();
86 _activatorsByType.Add(dataType, factory);
97 public static object Clone(
object instanceToClone)
99 var type = instanceToClone.GetType();
101 if (_cloneMethodsByType.TryGetValue(type, out func))
103 return func(
null, instanceToClone);
107 var method = typeof (CloneFactory).GetMethods().FirstOrDefault(x => x.Name ==
"GetClone" && x.GetParameters().Length == 1);
108 method = method.MakeGenericMethod(type);
109 func = method.DelegateForCallMethod();
110 _cloneMethodsByType[type] = func;
111 return func(
null, instanceToClone);
117 public static T
Clone<T>(T instanceToClone) where T :
class
119 var clone =
Clone((
object)instanceToClone) as T;
122 throw new ArgumentException($
"Unable to clone instance of type {instanceToClone.GetType().Name} to {typeof(T).Name}");
132 public static void AddActivator(Type key, Func<
object[],
object> value)
134 if (!_activatorsByType.ContainsKey(key))
136 _activatorsByType.Add(key, value);
140 throw new ArgumentException($
"ObjectActivator.AddActivator(): a method to return an instance of {key.Name} has already been added");
149 _activatorsByType.Clear();