I'm trying to improve the performance of our application. We have a lot of Activator.CreateInstance calls that are causing some grief.
We instantiate a lot of classes based on an interface (ITabDocument) and after looking around I thought of using this code:
The code is no better (infact marginally slower) than using the Activator.CreateInstance code we had.
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>));
}
I'm wondering why this is, all I'm doing is:
ITabDocument document = CreateInstance<ITabDocument>(Type.GetType("[Company].Something"));
Is there a better way of creating objects which would assist with the above? Its a little hard when you're not sure of the concrete type.
I did some benchmarking between these (I would write down the bare minimum details):
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
As CD says compiled expression is the fastest, and by a big margin. All the methods except (T)FormatterServices.GetUninitializedObject(typeof(T))
work only for types with default constructor.
And caching the compiled resultant delegate is trivial when you have a static class per generic type. Like:
public static class New<T> where T : new()
{
public static readonly Func<T> Instance = Expression.Lambda<Func<T>>
(
Expression.New(typeof(T))
).Compile();
}
Note the new
constraint. Call anything
MyType me = New<MyType>.Instance();
Except for the first time the class is being loaded in memory, the execution is going to be fastest.
To have a class that handles both types with default constructor and without, I took a hybrid approach, from here:
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;
}
Will handle value types too in an efficient manner.
Note that (T)FormatterServices.GetUninitializedObject(t)
will fail for string
. Hence special handling for string is in place to return empty string.
typeof(T)
). - nawfal
This might help: Don’t use Activator.CreateInstance or ConstructorInfo.Invoke, use compiled lambda expressions:
// 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();
The problem is if your are going to call CreateInstance over and over again directly rather than saving the result somewhere and using that result over and over again, you should probably just go ahead and do you caching inside of it.
internal static class DelegateStore<T> {
internal static IDictionary<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();
}
DelegateStore<T>
class at all because that generic class automatically gets a unique per-T
instantiation already. This is true even though it is a static
class. So all you need in DelegateStore<T>
is simply internal static Func<T> _cached_func;
As you have it, you're creating many dictionaries--a new one for every T
--each containing just one single cached delegate. - Glenn Slayden
You're probably getting some overhead from the generation of the same code.
The ILGenerator
dynamically creates code for the factory.
Create somekind of map or Dictionary
of types you've already used, and keep the factory method created for that type.
Generic method for constructing delegates, calling constructor directly. Automatically searches constructor in given type with signature of given delegate type and constructs delegate of that type. Code here:
/// <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);
}
}
is part of Yappi project's sources. Using it you can construct delegate calling any constructor of given type, including constructor with parameters (except ref and out parameters).
Sample usage:
var newList = Constructor.Compile<Func<int, IList<String>>>(typeof (List<String>));
var list = newList(100);
After construction of delegate, store it somewhere in static dictionary or in static field of class with generic parameter. Don't construct new delegate each time. Use one delegate for constructing multiple instances of given type.
CreateInstance
- because the whole point of that is that you'd callCreateInstance
once but then remember the factory delegate. If you're callingCreateInstance
on each operation, then yes, it'll be slower... - Jon Skeet