Ответ 1
Используйте скомпилированную лямбду, если можете, ее МНОГО быстрее.
Я использую RedGate для оценки производительности. Я замечаю, что динамическое создание экземпляра с использованием Activator.CreateInstance
(с двумя параметрами конструктора) занимает достойное количество времени... есть ли лучшая альтернатива, которая все еще использует рефлексивный подход (не явный экземпляр)?
Используйте скомпилированную лямбду, если можете, ее МНОГО быстрее.
Не забывайте о DynamicMethod
Здесь пример создания нового экземпляра по умолчанию по умолчанию
public static ObjectActivator CreateCtor(Type type)
{
if (type == null)
{
throw new NullReferenceException("type");
}
ConstructorInfo emptyConstructor = type.GetConstructor(Type.EmptyTypes);
var dynamicMethod = new DynamicMethod("CreateInstance", type, Type.EmptyTypes, true);
ILGenerator ilGenerator = dynamicMethod.GetILGenerator();
ilGenerator.Emit(OpCodes.Nop);
ilGenerator.Emit(OpCodes.Newobj, emptyConstructor);
ilGenerator.Emit(OpCodes.Ret);
return (ObjectActivator)dynamicMethod.CreateDelegate(typeof(ObjectActivator));
}
public delegate object ObjectActivator();
здесь больше о сравнение производительности
Измерение InvokeMember... 1000000 итераций в 1.5643784 секунды.
Измерение MethodInfo.Invoke... 1000000 итераций в 0.8150111 секунд.
Измерение DynamicMethod... 1000000 итераций за 0.0330202 секунд.
Измерение прямого вызова... 1000000 итераций в 0.0136752 секунд.
Я создал решение, которое можно использовать в качестве замены для Activator.CreateInstance
. Вы можете найти это в моем блоге.
Пример:
var myInstance = InstanceFactory.CreateInstance(typeof(MyClass));
var myArray1 = InstanceFactory.CreateInstance(typeof(int[]), 1024);
var myArray2 = InstanceFactory.CreateInstance(typeof(int[]), new object[] { 1024 });
Код:
public static class InstanceFactory
{
private delegate object CreateDelegate(Type type, object arg1, object arg2, object arg3);
private static ConcurrentDictionary<Tuple<Type, Type, Type, Type>, CreateDelegate> cachedFuncs = new ConcurrentDictionary<Tuple<Type, Type, Type, Type>, CreateDelegate>();
public static object CreateInstance(Type type)
{
return InstanceFactoryGeneric<TypeToIgnore, TypeToIgnore, TypeToIgnore>.CreateInstance(type, null, null, null);
}
public static object CreateInstance<TArg1>(Type type, TArg1 arg1)
{
return InstanceFactoryGeneric<TArg1, TypeToIgnore, TypeToIgnore>.CreateInstance(type, arg1, null, null);
}
public static object CreateInstance<TArg1, TArg2>(Type type, TArg1 arg1, TArg2 arg2)
{
return InstanceFactoryGeneric<TArg1, TArg2, TypeToIgnore>.CreateInstance(type, arg1, arg2, null);
}
public static object CreateInstance<TArg1, TArg2, TArg3>(Type type, TArg1 arg1, TArg2 arg2, TArg3 arg3)
{
return InstanceFactoryGeneric<TArg1, TArg2, TArg3>.CreateInstance(type, arg1, arg2, arg3);
}
public static object CreateInstance(Type type, params object[] args)
{
if (args == null)
return CreateInstance(type);
if (args.Length > 3 ||
(args.Length > 0 && args[0] == null) ||
(args.Length > 1 && args[1] == null) ||
(args.Length > 2 && args[2] == null))
{
return Activator.CreateInstance(type, args);
}
var arg0 = args.Length > 0 ? args[0] : null;
var arg1 = args.Length > 1 ? args[1] : null;
var arg2 = args.Length > 2 ? args[2] : null;
var key = Tuple.Create(
type,
arg0?.GetType() ?? typeof(TypeToIgnore),
arg1?.GetType() ?? typeof(TypeToIgnore),
arg2?.GetType() ?? typeof(TypeToIgnore));
if (cachedFuncs.TryGetValue(key, out CreateDelegate func))
return func(type, arg0, arg1, arg2);
else
return CacheFunc(key)(type, arg0, arg1, arg2);
}
private static CreateDelegate CacheFunc(Tuple<Type, Type, Type, Type> key)
{
var types = new Type[] { key.Item1, key.Item2, key.Item3, key.Item4 };
var method = typeof(InstanceFactory).GetMethods()
.Where(m => m.Name == "CreateInstance")
.Where(m => m.GetParameters().Count() == 4).Single();
var generic = method.MakeGenericMethod(new Type[] { key.Item2, key.Item3, key.Item4 });
var paramExpr = new List<ParameterExpression>();
paramExpr.Add(Expression.Parameter(typeof(Type)));
for (int i = 0; i < 3; i++)
paramExpr.Add(Expression.Parameter(typeof(object)));
var callParamExpr = new List<Expression>();
callParamExpr.Add(paramExpr[0]);
for (int i = 1; i < 4; i++)
callParamExpr.Add(Expression.Convert(paramExpr[i], types[i]));
var callExpr = Expression.Call(generic, callParamExpr);
var lambdaExpr = Expression.Lambda<CreateDelegate>(callExpr, paramExpr);
var func = lambdaExpr.Compile();
cachedFuncs.TryAdd(key, func);
return func;
}
}
public static class InstanceFactoryGeneric<TArg1, TArg2, TArg3>
{
private static ConcurrentDictionary<Type, Func<TArg1, TArg2, TArg3, object>> cachedFuncs = new ConcurrentDictionary<Type, Func<TArg1, TArg2, TArg3, object>>();
public static object CreateInstance(Type type, TArg1 arg1, TArg2 arg2, TArg3 arg3)
{
if (cachedFuncs.TryGetValue(type, out Func<TArg1, TArg2, TArg3, object> func))
return func(arg1, arg2, arg3);
else
return CacheFunc(type, arg1, arg2, arg3)(arg1, arg2, arg3);
}
private static Func<TArg1, TArg2, TArg3, object> CacheFunc(Type type, TArg1 arg1, TArg2 arg2, TArg3 arg3)
{
var constructorTypes = new List<Type>();
if (typeof(TArg1) != typeof(TypeToIgnore))
constructorTypes.Add(typeof(TArg1));
if (typeof(TArg2) != typeof(TypeToIgnore))
constructorTypes.Add(typeof(TArg2));
if (typeof(TArg3) != typeof(TypeToIgnore))
constructorTypes.Add(typeof(TArg3));
var parameters = new List<ParameterExpression>()
{
Expression.Parameter(typeof(TArg1)),
Expression.Parameter(typeof(TArg2)),
Expression.Parameter(typeof(TArg3)),
};
var constructor = type.GetConstructor(constructorTypes.ToArray());
var constructorParameters = parameters.Take(constructorTypes.Count).ToList();
var newExpr = Expression.New(constructor, constructorParameters);
var lambdaExpr = Expression.Lambda<Func<TArg1, TArg2, TArg3, object>>(newExpr, parameters);
var func = lambdaExpr.Compile();
cachedFuncs.TryAdd(type, func);
return func;
}
}
public class TypeToIgnore
{
}