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 a 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:
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
Pingback: DotNetShoutout
Pingback: Interesting .NET Links - December 30 , 2011 | Tech Blog
I don’t understand why you would want to be able to instantiate from private constructors. There’s generally a reason for creating a constructor as private, that being that you don’t want it to be called.
Not my call, I just provided a solution, but right of my head….
E.g in a deserialization/mapping scenario. Normal consumers should not be “allowed” to use a certain constructor, whilst your tooling that perhaps create an instance and the populate certain members on it.
//Daniel
There are certainly new points to learn. thanks a lot.
Nice One..