We use a lot of thought to call Activator.CreateInstance to create new objects in our code, but based on this article, it is better to use a compiled lambda expression to improve performance. So I created a static function that creates an intance of a class with lambda expressions:
public static class ClassBuilder
{
private delegate T ObjectActivator<T>(params object[] args);
public static T CreateInstance<T>(Type type, params object[] parameters)
{
if (type == null)
{
throw new ArgumentNullException(nameof(type));
}
if (parameters == null)
{
throw new ArgumentNullException(nameof(parameters));
}
Type[] typedArgs = new Type[parameters.Length];
for (int i = 0; i < parameters.Length; i++)
{
typedArgs[i] = parameters[i].GetType();
}
ConstructorInfo ctor = type.GetConstructor(typedArgs);
if (ctor != null)
{
ObjectActivator<T> createdActivator = GetActivator<T>(ctor);
return createdActivator(parameters);
}
else
{
throw new ArgumentException("Unable to find constructor with specified parameters.");
}
}
private static ObjectActivator<T> GetActivator<T>(ConstructorInfo ctor)
{
Type type = ctor.DeclaringType;
ParameterInfo[] paramsInfo = ctor.GetParameters();
ParameterExpression param = Expression.Parameter(typeof(object[]), "args");
Expression[] argsExp = new Expression[paramsInfo.Length];
for (int i = 0; i < paramsInfo.Length; i++)
{
Expression idx = Expression.Constant(i);
Type paramType = paramsInfo[i].ParameterType;
Expression paramAccessorExp = Expression.ArrayIndex(param, idx);
argsExp[i] = Expression.Convert(paramAccessorExp, paramType);
}
NewExpression newExp = Expression.New(ctor, argsExp);
LambdaExpression lambdaExpression = Expression.Lambda(typeof(ObjectActivator<T>), newExp, param);
ObjectActivator<T> compiledExpression = (ObjectActivator<T>)lambdaExpression.Compile();
return compiledExpression;
}
}
But after this implementation, I tried to profile 3 methods (Activator.CreateInstance, Inovke and Lambda Expression), creating 1000 instances of the object. I was really disappointed with the result of the lambda expression.
, "... , , , " .
, , ctor :
private static ConcurrentDictionary<object, object> _activatorCache = new ConcurrentDictionary<object, object>();
private static ObjectActivator<T> GetActivator<T>(ConstructorInfo ctor)
{
if (_activatorCache.ContainsKey(ctor))
{
return _activatorCache[ctor] as ObjectActivator<T>;
}
Type type = ctor.DeclaringType;
ParameterInfo[] paramsInfo = ctor.GetParameters();
...
ObjectActivator<T> compiledExpression = (ObjectActivator<T>)lambdaExpression.Compile();
_activatorCache[ctor] = compiledExpression;
}
, .
-, ?
ctor ?