Поделиться через


Using lambdas to create generic factories

One item I find to be limiting in C# is the new generic constraint.  The syntax construct specifies that the type backing a given generic parameter contains a parameter less constructor.   It allows methods to create instances of generic parameters in a type safe manner.

 public static void Example<T>() 
    where T : new()
{
    var value = new T();
    Process(value);
}

I find though that I very rarely want this capability.  The object can’t be provided any initial state since you can’t give it any values to the constructor. It’s really only useful if you want to create and then mutate a given object.   

Typically I prefer to deal with immutable data or at least types which build upon other information.  Hence my types tend to have constructors which take at least one piece of information.  In this case the new constraint is of no value because it can’t be used to describe arbitrary constructor signatures but is limited to only a parameter less constructor. 

 public static void Example<T>()
    where T : new(string) // Not possible!!!
{
    var value = new T("some data");

}

Originally when I faced this situation I ran to the factory pattern.  I created a nice IFactory<T> interface which had a Create method taking a string, and modified the methods to take this type instead. 

 public static void Example<T>(IFactory<T> factory) {
    var value = factory.Create("some data");
}

This works and there is nothing wrong with it.  Except of course it’s an extremely verbose solution.  Every time I want to use the method with a new type I have to create a new type which implements IFactory<MyNewType> just to call this method.   This is very tiresome and gets frustrating very fast with broad object hierarchies. 

Fortunately there is a much lighter weight solution to this problem: lambda expressions.  All we need in this instance is a method which given one or more pieces of input returns a new instance of T.  How this is implemented is of no concern to the method.  This can easily be done via a delegate. 

 public static void Example<T>(Func<string, T> createInstance) {
    var value = createInstance("some data");
}

Now the caller can provide the contract with a simple light weight lambda expression

 Example(data => new Widget(data));

Comments

  • Anonymous
    June 04, 2010
    Very cool - I talked about something similar (togaroga.com/.../two-structural-additions-to-c) but I was more hoping to see the C# team offer us richer generic constraint syntax to allow specific constructor signatures.  This is a very cool workaround though!

  • Anonymous
    June 04, 2010
    this is not so much about lambdas, as it is about "Func", lambdas is just an option you can use

  • Anonymous
    June 04, 2010
    If you think you might like library support for generalized type reasoning like this, check out Autofac. nblumhardt.com/.../the-relationship-zoo touches explicitly on this.

  • Anonymous
    June 15, 2010
    Hi Jared! Lack of generic constructor with parameters in c# is, in my opinion, a bad pitfall. It does limit  functional programming in c#: using generics and  immutable classes. F# doesn't have this kind of problems. Also, I feel that some simple syntax for making c# class with a parameterized constructor and (readonly) get- properties would make code lot shorter. I hope that in .NET 5.0 c# these things will be fixed. In a Channel 9 video of C# future, the language lead architect, Anders Hejlsberg, said that they will pay some attention to immutability. :-)