Fast version of the Activator.CreateInstance method using IL
FastObjectFactory.zip (50.35 kb)
We all know (I guess) the method Activator.CreateInstance(Type) and the generic version: Activator.CreateInstance<T>() that are used to create an instance of a specified Type.
In now days all are talking about 'Entity-relationship model' , 'Object-relational mapping' and that stuff, that basically it means getting a IDataReader, loop over it and fill with the data a List with specfied type of objects and return a List instead of DataSet or DataTable (or similar mechanism). While looping over the IDataReader, every iterate, an instance of the specified type needs to be create. It can be done using one of the methods above, but it can be improved by usind IL and some help using some cache. Here is how can it be done:
public static class FastObjectFactory
{
private static readonly Hashtable creatorCache = Hashtable.Synchronized(new Hashtable());
private readonly static Type coType = typeof(CreateObject);
public delegate object CreateObject();
/// <summary>
/// Create an object that will used as a 'factory' to the specified type T
/// <returns></returns>
public static CreateObject CreateObjectFactory<T>() 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;
}
}
Note the static HashTable is been used as a cache. The first time we create a delegate 'CreateObjec' for the given type it is 'slow', so all the point here, is to cache this delegate. The next time we need to create an object from the given type, the 'CreateObjec' delegate will be used from the cache. Without caching it, the whole story worth nothing.
Here are some benchmarks:
1 Object:
100 Objects:
1000 Objects:
Comparing to the generic constraint : new()
Below there is the small project I used for the benchmarks:
Posted in Labels: Architecture / Design, ASP.NET, C#, Technology News, Tricks, Visual Studio.NET | Edit |
0 comments:
Post a Comment