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'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;
}
}