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 Dictionary<Type, MethodInvoker> _cloneMethodsByType =
new Dictionary<Type, MethodInvoker>();
33 private static readonly Dictionary<Type, Func<object[], object>> _activatorsByType =
new Dictionary<Type, Func<object[], object>>();
38 ((HashSet<Type>) CloneFactory.KnownImmutableTypes).Add(typeof (
Symbol));
54 Func<object[], object> factory;
55 if (_activatorsByType.TryGetValue(dataType, out factory))
60 var ctor = dataType.GetConstructor(
new Type[] {});
63 if (ctor ==
null)
return null;
65 var paramsInfo = ctor.GetParameters();
68 var param = Expression.Parameter(typeof (
object[]),
"args");
69 var argsExp =
new Expression[paramsInfo.Length];
71 for (var i = 0; i < paramsInfo.Length; i++)
73 var index = Expression.Constant(i);
74 var paramType = paramsInfo[i].ParameterType;
75 var paramAccessorExp = Expression.ArrayIndex(param, index);
76 var paramCastExp = Expression.Convert(paramAccessorExp, paramType);
77 argsExp[i] = paramCastExp;
80 var newExp = Expression.New(ctor, argsExp);
81 var lambda = Expression.Lambda(typeof (Func<
object[],
object>), newExp, param);
82 factory = (Func<object[], object>) lambda.Compile();
85 _activatorsByType.Add(dataType, factory);
96 public static object Clone(
object instanceToClone)
98 var type = instanceToClone.GetType();
100 if (_cloneMethodsByType.TryGetValue(type, out func))
102 return func(
null, instanceToClone);
106 var method = typeof (CloneFactory).GetMethods().FirstOrDefault(x => x.Name ==
"GetClone" && x.GetParameters().Length == 1);
107 method = method.MakeGenericMethod(type);
108 func = method.DelegateForCallMethod();
109 _cloneMethodsByType[type] = func;
110 return func(
null, instanceToClone);
116 public static T
Clone<T>(T instanceToClone) where T :
class
118 var clone =
Clone((
object)instanceToClone) as T;
121 throw new ArgumentException($
"Unable to clone instance of type {instanceToClone.GetType().Name} to {typeof(T).Name}");
131 public static void AddActivator(Type key, Func<
object[],
object> value)
133 if (!_activatorsByType.ContainsKey(key))
135 _activatorsByType.Add(key, value);
139 throw new ArgumentException($
"ObjectActivator.AddActivator(): a method to return an instance of {key.Name} has already been added");
148 _activatorsByType.Clear();