我已经对此进行了一些测试,作为 Miron 原始文章(此处)的后续,我发现 .NET 4.0 Activator 比以前快得多。他的应用程序版本的一些结果经过调整,以毫秒为单位显示时间:
.NET 3.5 build
Number of iterates: 1000000
Activator.CreateInstance(Type): 4150
Activator.CreateInstance<T>(): 1288
FastObjectFactory.CreateObjec (empty cache): 33
FastObjectFactory.CreateObjec (cache full): 28
ItemFactory.GetNewItem: 1283
.NET 4.0 build
Number of iterates: 1000000
Activator.CreateInstance(Type): 138
Activator.CreateInstance<T>(): 151
FastObjectFactory.CreateObjec (empty cache): 28
FastObjectFactory.CreateObjec (cache full): 22
ItemFactory.GetNewItem: 156
然而,这是针对无参数构造函数的,我还注意到,当使用带参数的构造函数时,激活器仍然有点慢,如下所示。
我在此处发布的原始解决方案遇到的一个问题是,我不一定知道在编译时我想要的对象的类型——我只有一个类型引用。现在(除非我是个笨蛋)这意味着我不能在这里使用通用解决方案或对其进行简单的变体。
所以这是我拼凑的一个版本,可以解决这个问题。当使用构造函数参数时,它还显示了 .NET 4.0 Activator 中的轻微缓慢:
// For use with no-parameter constructors. Also contains constants and utility methods
public static class FastActivator
{
// THIS VERSION NOT THREAD SAFE YET
static Dictionary<Type, Func<object>> constructorCache = new Dictionary<Type, Func<object>>();
private const string DynamicMethodPrefix = "DM$_FastActivator_";
public static object CreateInstance(Type objType)
{
return GetConstructor(objType)();
}
public static Func<object> GetConstructor(Type objType)
{
Func<object> constructor;
if (!constructorCache.TryGetValue(objType, out constructor))
{
constructor = (Func<object>)FastActivator.BuildConstructorDelegate(objType, typeof(Func<object>), new Type[] { });
constructorCache.Add(objType, constructor);
}
return constructor;
}
public static object BuildConstructorDelegate(Type objType, Type delegateType, Type[] argTypes)
{
var dynMethod = new DynamicMethod(DynamicMethodPrefix + objType.Name + "$" + argTypes.Length.ToString(), objType, argTypes, objType);
ILGenerator ilGen = dynMethod.GetILGenerator();
for (int argIdx = 0; argIdx < argTypes.Length; argIdx++)
{
ilGen.Emit(OpCodes.Ldarg, argIdx);
}
ilGen.Emit(OpCodes.Newobj, objType.GetConstructor(argTypes));
ilGen.Emit(OpCodes.Ret);
return dynMethod.CreateDelegate(delegateType);
}
}
// For use with one-parameter constructors, argument type = T1
public static class FastActivator<T1>
{
// THIS VERSION NOT THREAD SAFE YET
static Dictionary<Type, Func<T1, object>> constructorCache = new Dictionary<Type, Func<T1, object>>();
public static object CreateInstance(Type objType, T1 arg1)
{
return GetConstructor(objType, new Type[] { typeof(T1) })(arg1);
}
public static Func<T1, object> GetConstructor(Type objType, Type[] argTypes)
{
Func<T1, object> constructor;
if (!constructorCache.TryGetValue(objType, out constructor))
{
constructor = (Func<T1, object>)FastActivator.BuildConstructorDelegate(objType, typeof(Func<T1, object>), argTypes);
constructorCache.Add(objType, constructor);
}
return constructor;
}
}
// For use with two-parameter constructors, argument types = T1, T2
public static class FastActivator<T1, T2>
{
// THIS VERSION NOT THREAD SAFE YET
static Dictionary<Type, Func<T1, T2, object>> constructorCache = new Dictionary<Type, Func<T1, T2, object>>();
public static object CreateInstance(Type objType, T1 arg1, T2 arg2)
{
return GetConstructor(objType, new Type[] { typeof(T1), typeof(T2) })(arg1, arg2);
}
public static Func<T1, T2, object> GetConstructor(Type objType, Type[] argTypes)
{
Func<T1, T2, object> constructor;
if (!constructorCache.TryGetValue(objType, out constructor))
{
constructor = (Func<T1, T2, object>)FastActivator.BuildConstructorDelegate(objType, typeof(Func<T1, T2, object>), argTypes);
constructorCache.Add(objType, constructor);
}
return constructor;
}
}
// For use with three-parameter constructors, argument types = T1, T2, T3
// NB: could possibly merge these FastActivator<T1,...> classes and avoid generic type parameters
// but would need to take care that cache entries were keyed to distinguish constructors having
// the same number of parameters but of different types. Keep separate for now.
public static class FastActivator<T1, T2, T3>
{
// THIS VERSION NOT THREAD SAFE YET
static Dictionary<Type, Func<T1, T2, T3, object>> constructorCache = new Dictionary<Type, Func<T1, T2, T3, object>>();
public static object CreateInstance(Type objType, T1 arg1, T2 arg2, T3 arg3)
{
return GetConstructor(objType, new Type[] { typeof(T1), typeof(T2), typeof(T3) })(arg1, arg2, arg3);
}
public static Func<T1, T2, T3, object> GetConstructor(Type objType, Type[] argTypes)
{
Func<T1, T2, T3, object> constructor;
if (!constructorCache.TryGetValue(objType, out constructor))
{
constructor = (Func<T1, T2, T3, object>)FastActivator.BuildConstructorDelegate(objType, typeof(Func<T1, T2, T3, object>), argTypes);
constructorCache.Add(objType, constructor);
}
return constructor;
}
}
下面是一些性能结果。请注意,这是再次以毫秒为单位创建 100 万个对象和计时:
Activator.CreateInstance(objType) - parameterless constructor: 153
FastActivator.CreateInstance(objType) - parameterless constructor: 86
Using FastActivator.GetConstructor and calling it repeatedly - parameterless constructor: 34
Activator.CreateInstance(objType) with 1 constructor arg: 3183
FastActivator.CreateInstance(objType) with 1 constructor arg: 257
FastActivator.GetConstructor and calling it repeatedly with 1 constructor arg: 126
Activator.CreateInstance(objType) with 3 constructor args: 4403
FastActivator.CreateInstance(objType) with 3 constructor args: 640
FastActivator.GetConstructor and calling it repeatedly with 3 constructor args : 405
FastActivator.GetConstructor and calling it repeatedly with 3 constructor args; args created only once : 19