我正在使用RedGate进行一些性能评估。我注意到使用Activator.CreateInstance
动态创建一个实例(带有两个构造函数参数)花费了相当多的时间......是否有更好的替代方法仍然使用反射方法(不是显式实例化)?
答案 0 :(得分:40)
如果可以的话,使用已编译的lambda,其速度更快。
答案 1 :(得分:13)
以下是如何通过默认构造函数
创建新实例的示例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 ...在1.5643784秒内完成1000000次迭代。
测量MethodInfo.Invoke ...在0.8150111秒内进行1000000次迭代。
测量DynamicMethod ...在0.0330202秒内进行1000000次迭代。
测量直接呼叫...在0.0136752秒内进行1000000次迭代。
答案 2 :(得分:0)
我创建了一个解决方案,可以代替Activator.CreateInstance
。您可以在我的blog上找到它。
示例:
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
{
}