Today I got involved in a small question on Twitter on how to create a generic factory creating instances of classes having a private constructor. So I put together a small sample that shows two solutions:
- Using Activator (around 22s per 100000)
- Using compiled lambdas (around 8s per 100000)
The example lets you time the difference between the solutions. And feel free to add the code using IL. Please note! This was something I put together really quick so there's probably some room left for you to tweak.
The source code is also made availible as a Gist here: https://gist.github.com/1529618">https://gist.github.com/1529618
Sample model
public interface IPerson
{
string Name { get; set; }
}
public class Person : IPerson
{
public string Name { get; set; }
private Person() { }
}
The factory
public static class Factory<T> where T : class
{
private static readonly Func<T> FactoryFn;
static Factory()
{
//FactoryFn = CreateUsingActivator();
FactoryFn = CreateUsingLambdas();
}
private static Func<T> CreateUsingActivator()
{
var type = typeof(T);
Func<T> f = () => Activator.CreateInstance(type, true) as T;
return f;
}
private static Func<T> CreateUsingLambdas()
{
var type = typeof(T);
var ctor = type.GetConstructor(
BindingFlags.Instance | BindingFlags.CreateInstance |
BindingFlags.NonPublic,
null, new Type[] { }, null);
var ctorExpression = Expression.New(ctor);
return Expression.Lambda<Func<T>>(ctorExpression).Compile();
}
public static T Create(Action<T> init)
{
var instance = FactoryFn();
init(instance);
return instance;
}
}
The test app
class Program
{
static void Main(string[] args)
{
//TOUCH ONCE BEFORE TIMING
var touchedPerson =
Factory<Person>.Create(p => p.Name = "Daniel");
for (var a = 0; a < 5; a++)
{
var sw = Stopwatch.StartNew();
for (int c = 0; c < 100000; c++)
{
var person =
Factory<Person>.Create(p => p.Name = "Daniel");
var n = person.Name;
}
sw.Stop();
Console.WriteLine(sw.Elapsed.TotalMilliseconds);
}
Console.ReadKey();
}
}
That's it. Enjoy!
//Daniel