How to pass ctor args in Activator.CreateInstance or use IL?
.net, createinstance, il, parameters, performance
Solution
I'm putting this up as the so far best performant object creation factory so far using the current (2010-01-11) answers, according to my tests. I did notice that using cache works best when iterations are somewhere below 99,999. If you are going to load more than 99,999 it is best to not use cache. Because this could be the case I've created something that would allow you to use cache or not. My current project will sometimes load millions of records and at other times only load one. Anyways, I'm putting this out there to see what your thoughts are. Note that the code below is for ctor's that have 1 arg, one would have to create a similar factory for more than 1 arg ctor.
// code updated 2010-06-01
// class that creates comment objects
public class CreatesSomeObject
{
// method that creates a comment object
public void CreateComment()
{
// Method 1 (without cache)
Comment comment1 = ObjectFactoryFactory<Comment, ObjectId>
.CreateObject.Invoke(new ObjectId());
// Method 2 (with cache)
Comment comment2 = ObjectFactoryFactory<Comment, ObjectId>
.CreateObjectWithCache.Invoke(new ObjectId());
// Method 3 (without helper factory ObjectFactoryFactory)
Comment comment3 = ObjectFactory<Comment, ObjectId>
.CreateObject.Invoke(new ObjectId());
}
}
// This is optional class. Just helps in creating objects when
// a cache is needed or not needed.
public static class ObjectFactoryFactory<T, P1> where T : class
{
static Hashtable cache = Hashtable.Synchronized(new Hashtable());
public static Func<P1, T> CreateObject
{
get { return ObjectFactory<T, P1>.CreateObject; }
}
public static Func<P1, T> CreateObjectWithCache
{
get
{
return ObjectFactory<T, P1>.UseCache(cache);
}
}
}
// Main object creation factory class.
public static class ObjectFactory<T, P1> where T : class
{
static Func<P1, T> _createObject;
public static Func<P1, T> CreateObject
{
get
{
if (_createObject != null) return _createObject;
_createObject = CreateDelegate();
return _createObject;
}
}
static Func<P1, T> CreateDelegate()
{
Type objType = typeof(T);
Type[] types = new[] { typeof(P1) };
var dynMethod = new DynamicMethod("DM$OBJ_FACTORY_" +
objType.Name, objType, types, objType);
ILGenerator ilGen = dynMethod.GetILGenerator();
// if need more than 1 arg add another Ldarg_x
// you'll also need to add proper generics and
// CreateDelegate signatures
ilGen.Emit(OpCodes.Ldarg_0);
ilGen.Emit(OpCodes.Newobj, objType.GetConstructor(types));
ilGen.Emit(OpCodes.Ret);
return (Func<P1, T>)dynMethod.CreateDelegate(typeof(Func<P1, T>));
}
public static Func<P1, T> UseCache(Hashtable cache)
{
Type t = typeof(T);
Func<P1, T> c = cache[t] as Func<P1, T>;
if (c == null)
{
lock (cache.SyncRoot)
{
c = cache[t] as Func<P1, T>;
if (c != null)
{
return c;
}
c = CreateDelegate();
cache.Add(t, c);
}
}
return c;
}
}
Problem
I need a performance enhanced Activator.CreateInstance() and came across this article by Miron Abramson that uses a factory to create the instance in IL and then cache it. (I've included code below from Miron Abramson's site in case it somehow disappears). I'm new to IL Emit code and anything beyond Activator.CreateInstance() for instantiating a class and any help would be much appreciative. My problem is that I need to create an instance of an object that takes a ctor with a parameter. I see there is a way to pass in the Type of the parameter, but is there a way to pass in the value of the ctor parameter as well? If possible, I would like to use a method similar to `CreateObjectFactory<T>(params object[] constructorParams)` as some objects I want to instantiate may have more than 1 ctor param. ``` // 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; } } ``` Update to Miron's code from commentor on his post 2010-01-11 ``` 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>)); } } ```