Альтернатива производительности Activator.CreateInstance - PullRequest
34 голосов
/ 13 декабря 2010

Я использую RedGate для оценки производительности. Я заметил, что динамическое создание экземпляра с использованием Activator.CreateInstance (с двумя параметрами конструктора) занимает приличное количество времени ... есть ли лучшая альтернатива, которая все еще использует рефлексивный подход (не явное создание экземпляров)?

Ответы [ 3 ]

40 голосов
/ 13 декабря 2010

Используйте скомпилированную лямбду, если можете, она НАМНОГО быстрее.

https://vagifabilov.wordpress.com/2010/04/02/dont-use-activator-createinstance-or-constructorinfo-invoke-use-compiled-lambda-expressions/

14 голосов
/ 02 мая 2014

Не забудьте про 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 секунды.

0 голосов
/ 28 декабря 2018

Я создал решение, которое можно использовать как замену 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
{
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...