Activator.CreateInstance Performance Alternative

前端 未结 3 1768
情话喂你
情话喂你 2020-12-07 22:34

I\'m using RedGate to do some performance evaluation. I notice dynamically creating an instance using Activator.CreateInstance (with two constructor parameters

相关标签:
3条回答
  • 2020-12-07 23:04

    Don't forget about DynamicMethod

    Here's example how to create new instance thru default constructor

    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();
    

    here's more about performance comparison

    Measuring InvokeMember... 1000000 iterations in 1.5643784 seconds.

    Measuring MethodInfo.Invoke... 1000000 iterations in 0.8150111 seconds.

    Measuring DynamicMethod... 1000000 iterations in 0.0330202 seconds.

    Measuring direct call... 1000000 iterations in 0.0136752 seconds.

    0 讨论(0)
  • 2020-12-07 23:09

    Use a compiled lambda if you can, its MUCH faster.

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

    0 讨论(0)
  • 2020-12-07 23:15

    I have created a solution that can be used as a drop in replacement for Activator.CreateInstance. You can find it on my blog.

    Example:

    var myInstance = InstanceFactory.CreateInstance(typeof(MyClass));
    var myArray1 = InstanceFactory.CreateInstance(typeof(int[]), 1024);
    var myArray2 = InstanceFactory.CreateInstance(typeof(int[]), new object[] { 1024 });
    

    Code:

    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
    {
    }
    
    0 讨论(0)
提交回复
热议问题