作者热门文章
- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我需要一个性能增强的 Activator.CreateInstance() 并且遇到了 this article Miron Abramson 使用工厂在 IL 中创建实例,然后缓存它。 (我在下面包含了来自 Miron Abramson 网站的代码,以防它以某种方式消失)。我是 IL Emit 代码的新手,除了 Activator.CreateInstance() 之外的任何用于实例化类的东西,任何帮助都会非常感激。
我的问题是我需要创建一个带有参数的 ctor 的对象实例。我看到有一种方法可以传入参数的类型,但是有没有一种方法可以传入 ctor 参数的值?
如果可能,我想使用类似于 CreateObjectFactory<T>(params object[] constructorParams)
的方法。因为我想实例化的一些对象可能有超过 1 个 ctor 参数。
// Source: http://mironabramson.com/blog/post/2008/08/Fast-version-of-the-ActivatorCreateInstance-method-using-IL.aspx
public static class FastObjectFactory
{
private static readonly Hashtable creatorCache = Hashtable.Synchronized(new Hashtable());
private readonly static Type coType = typeof(CreateObject);
public delegate object CreateObject();
///
/// Create an object that will used as a 'factory' to the specified type T
///
public static CreateObject CreateObjectFactory() where T : class
{
Type t = typeof(T);
FastObjectFactory.CreateObject c = creatorCache[t] as FastObjectFactory.CreateObject;
if (c == null)
{
lock (creatorCache.SyncRoot)
{
c = creatorCache[t] as FastObjectFactory.CreateObject;
if (c != null)
{
return c;
}
DynamicMethod dynMethod = new DynamicMethod("DM$OBJ_FACTORY_" + t.Name, typeof(object), null, t);
ILGenerator ilGen = dynMethod.GetILGenerator();
ilGen.Emit(OpCodes.Newobj, t.GetConstructor(Type.EmptyTypes));
ilGen.Emit(OpCodes.Ret);
c = (CreateObject)dynMethod.CreateDelegate(coType);
creatorCache.Add(t, c);
}
}
return c;
}
}
public static class FastObjectFactory2<T> where T : class, new()
{
public static Func<T> CreateObject { get; private set; }
static FastObjectFactory2()
{
Type objType = typeof(T);
var dynMethod = new DynamicMethod("DM$OBJ_FACTORY_" + objType.Name, objType, null, objType);
ILGenerator ilGen = dynMethod.GetILGenerator();
ilGen.Emit(OpCodes.Newobj, objType.GetConstructor(Type.EmptyTypes));
ilGen.Emit(OpCodes.Ret);
CreateObject = (Func<T>)
dynMethod.CreateDelegate(typeof(Func<T>));
}
}
最佳答案
我一直在对此进行一些测试,作为 Miron 原始文章 (here) 的后续内容,我发现 .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
// 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;
}
}
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
关于.net - 如何在 Activator.CreateInstance 中传递 ctor args 或使用 IL?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2024435/
我是一名优秀的程序员,十分优秀!