快速创build对象而不是Activator.CreateInstance(type)
我试图改善我们的应用程序的性能。 我们有很多Activator.CreateInstance调用导致一些悲伤。
我们基于一个接口(ITabDocument)来实例化很多类,然后环顾四周,我想到了使用这个代码:
代码不会比使用我们拥有的Activator.CreateInstance代码更好。
public static Func<T> CreateInstance<T>(Type objType) where T : class, new() { 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); return (Func<T>)dynMethod.CreateDelegate(typeof(Func<T>)); }
我想知道为什么这是我所做的是:
ITabDocument document = CreateInstance<ITabDocument>(Type.GetType("[Company].Something"));
有没有更好的方法来创build可以协助上述的对象? 当你不确定具体types时有点难。
我做了一些基准之间(我会写下最基本的细节):
public static T Instance() //~1800 ms { return new T(); } public static T Instance() //~1800 ms { return new Activator.CreateInstance<T>(); } public static readonly Func<T> Instance = () => new T(); //~1800 ms public static readonly Func<T> Instance = () => Activator.CreateInstance<T>(); //~1800 ms //works for types with no default constructor as well public static readonly Func<T> Instance = () => (T)FormatterServices.GetUninitializedObject(typeof(T)); //~2000 ms public static readonly Func<T> Instance = Expression.Lambda<Func<T>>(Expression.New(typeof(T))).Compile(); //~50 ms for classes and ~100 ms for structs
由于光盘编译expression是最快的,而且是一个很大的余地。 除(T)FormatterServices.GetUninitializedObject(typeof(T))
之外的所有方法仅适用于具有默认构造函数的types。
如果每个genericstypes都有一个静态类,那么caching编译的结果委托就是微不足道的。 喜欢:
public static class New<T> where T : new() { public static readonly Func<T> Instance = Expression.Lambda<Func<T>> ( Expression.New(typeof(T)) ).Compile(); }
注意new
约束。 拨打任何东西
MyType me = New<MyType>.Instance();
除了第一次将这个类加载到内存中,执行速度将是最快的。
要使用默认构造函数处理这两种types的类,我从这里采取了一种混合方法:
public static class New<T> { public static readonly Func<T> Instance = Creator(); static Func<T> Creator() { Type t = typeof(T); if (t == typeof(string)) return Expression.Lambda<Func<T>>(Expression.Constant(string.Empty)).Compile(); if (t.HasDefaultConstructor()) return Expression.Lambda<Func<T>>(Expression.New(t)).Compile(); return () => (T)FormatterServices.GetUninitializedObject(t); } } public static bool HasDefaultConstructor(this Type t) { return t.IsValueType || t.GetConstructor(Type.EmptyTypes) != null; }
将以有效的方式处理值types。
请注意(T)FormatterServices.GetUninitializedObject(t)
将失败的string
。 因此,对string进行特殊处理以返回空string。
这可能有所帮助: 不要使用Activator.CreateInstance或ConstructorInfo.Invoke,使用编译的lambdaexpression式 :
// Make a NewExpression that calls the ctor with the args we just created NewExpression newExp = Expression.New(ctor, argsExp); // Create a lambda with the New expression as body and our param object[] as arg LambdaExpression lambda = Expression.Lambda(typeof(ObjectActivator), newExp, param); // Compile it ObjectActivator compiled = (ObjectActivator)lambda.Compile();
问题在于,如果您要直接调用CreateInstance,而不是将结果保存到某个地方,并一遍又一遍地使用该结果,那么您应该继续进行,并在内部进行caching。
internal static class DelegateStore<T>{ internal static IDictionnary<string, Func<T>> Store =new ConcurrentDictionary<string,Func<T>>(); } public static T CreateInstance<T>(Type objType) where T : class { Func<T> returnFunc; if(!DelegateStore<T>.Store.TryGetValue(objType.FullName, out returnFunc)){ 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); returnFunc =(Func<T>)dynMethod.CreateDelegate(typeof(Func<T>)); DelegateStore<T>.Store[objType.FullName]=returnfunc; } return returnFunc(); }
您可能从相同的代码中获得一些开销。
ILGenerator
dynamic地为工厂创build代码。
创build一些你已经使用过的types的地图或Dictionary
,并保持为该types创build的工厂方法。
用于构造委托的通用方法,直接调用构造函数。 自动search具有给定委托types签名的给定types的构造函数,并构造该types的委托。 代码在这里:
/// <summary> /// Reflective object construction helper. /// All methods are thread safe. /// </summary> public static class Constructor { /// <summary> /// Searches an instanceType constructor with delegateType-matching signature and constructs delegate of delegateType creating new instance of instanceType. /// Instance is casted to delegateTypes's return type. /// Delegate's return type must be assignable from instanceType. /// </summary> /// <param name="delegateType">Type of delegate, with constructor-corresponding signature to be constructed.</param> /// <param name="instanceType">Type of instance to be constructed.</param> /// <returns>Delegate of delegateType wich constructs instance of instanceType by calling corresponding instanceType constructor.</returns> public static Delegate Compile(Type delegateType,Type instanceType) { if (!typeof(Delegate).IsAssignableFrom(delegateType)) { throw new ArgumentException(String.Format("{0} is not a Delegate type.",delegateType.FullName),"delegateType"); } var invoke = delegateType.GetMethod("Invoke"); var parameterTypes = invoke.GetParameters().Select(pi => pi.ParameterType).ToArray(); var resultType = invoke.ReturnType; if(!resultType.IsAssignableFrom(instanceType)) { throw new ArgumentException(String.Format("Delegate's return type ({0}) is not assignable from {1}.",resultType.FullName,instanceType.FullName)); } var ctor = instanceType.GetConstructor( BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, parameterTypes, null); if(ctor == null) { throw new ArgumentException("Can't find constructor with delegate's signature","instanceType"); } var parapeters = parameterTypes.Select(Expression.Parameter).ToArray(); var newExpression = Expression.Lambda(delegateType, Expression.Convert(Expression.New(ctor, parapeters), resultType), parapeters); var @delegate = newExpression.Compile(); return @delegate; } public static TDelegate Compile<TDelegate>(Type instanceType) { return (TDelegate) (object) Compile(typeof (TDelegate), instanceType); } }
是Yappi项目的一部分。 使用它可以构造委托调用给定types的构造函数,包括带参数的构造函数(除ref和out参数外)。
示例用法:
var newList = Constructor.Compile<Func<int, IList<String>>>(typeof (List<String>)); var list = newList(100);
在构造完委托后,将其存储在静态字典或类的静态字段中的某个具有generics参数的地方。 不要每次构build新的委托。 使用一个委托来构造给定types的多个实例。