The “new()” constraint in Generics can be evil

Say I have a generic method of some sort, and one of the things that I do inside this method is to create an instance of the generic parameter. Something like this:

public class SomeUtilityClass
{
    public void DoSomething<T>() where T : new()
    {
        T myObj = new T();

        Console.WriteLine("Doing stuff with " + myObj.ToString());
    }
}

Users of that class could only use that method if specifying a type that has a default constructor (this gets enforced by the compiler):

var utility = new SomeUtilityClass();
utility.DoSomething<Customer>();

Now imagine I have something that looks like the following code:

public class CustomerPresenter
{
    private Repository m_Repository = new Repository();

    public Collection<ICustomer> Customers { get; set; }

    private void PopulateList()
    {
        Customers = m_Repository.GetList<ICustomer>();
    }
}

public class Repository
{
    public Collection<T> GetList<T>()
    {
        return new Collection<T>();
    }
}

The CustomerPresenter class has a Collection of ICustomer objects, which gets populated by calling GetList<ICustomer> on a repository object. This code is fairly generic: it works against any implementation of ICustomer. The application gets a concrete version of ICustomer by using a dependency injection container (not shown in the code here).

Now say I want to change the GetList method in the repository so it uses my “utility” class:

public Collection<T> GetList<T>()
{
    var utility = new SomeUtilityClass();   utility.DoSomething<T>();

    return new Collection<T>();
}

Unfortunately, the code above doesn’t compile, since DoSomething has the “new” constraint on its generic type, and the GetList doesn’t.

Hmm, ok, I’ll go ahead and add that same constraint to my GetList method:

public Collection<T> GetList<T>() where T : new()
{
   ...
}

That solves my problem with GetList, but it breaks the CustomerPresenter class:

public class CustomerPresenter
{
    private Repository m_Repository = new Repository();

    public Collection<ICustomer> Customers { get; set; }

    private void PopulateList()
    {
        Customers = m_Repository.GetList<ICustomer>();
    }
}

Again, notice that GetList is called with “ICustomer”, which is an interface, and as such, it doesn’t have a default constructor, so my code there doesn’t compile.

The quick fix for that would be to give up using the ICustomer interface, and use a concrete type instead. Well, that sucks, since I lose my flexibility of using whatever implementation of ICustomer I please.

It doesn’t matter how far I keep pushing the “new” constraint up the call chain; at some point I’ll have to give the method call a concrete type that satisfies the constraint. To keep things simple here, I’m hiding the fact that CustomerPresenter also is based on an interface, which defines “Customers” property.

The point that I’m trying to make here is that, in order to use that utility class’ method, I’ll have to make many severe changes to the application’s design. That’s not good at all.

So what’s the solution for this dilemma?

The solution is to give up compile-time checking in favor of some runtime checking, and use either Reflection, DynamicMethod, or an Expression Tree to instantiate that generic type:

public class SomeUtilityClass
{
    public void DoSomething<T>(Type objType)
    {
        T myObj = (T)CreateInstance(objType);

        Console.WriteLine("Doing stuff with " + myObj.ToString());
    }

    private object CreateInstance(Type objType)
    {
        // instantiate objType and return it
        return theInstance;
    }
}

Notice I’ve dropped the “where T : new()” constraint off the DoSomething method. I’ve also changed the method’s signature, so it takes in a objType parameter of type Type (that’s a lot of “type”). The parameter is passed along to a CreateInstance method, which takes care of instantiating the type. The return of this method is then cast to the generic type of T.

In the real world version of this code, I have checks to make sure that the given type does have a default constructor, and also that it can cast to the T generic type. If the parameter doesn’t satisfy those things, I throw an exception. Again, this is the price I decided to pay: have the constraint validated during runtime, instead of compile time.

What did that buy me?

First of all, I can now use that DoSomething method anywhere in my code without having to change my design of other classes to include the “new” generic constraint. Second of all, the performance has improved.

One might think that we’d get a performance hit, but I actually got the opposite. Please check this other blog post for specific details on the price of object instantiation.

Just to give you some rough numbers:

Running the original code (the one that uses the generic “new” constraint) inside a loop that goes through 1.000 iterations took 0.2163048 seconds. The new code, using an Expression Tree, takes 0.2078632 seconds. Albeit small, that’s an improvement. If I increased the number of iterations to 1.000.000 (an unlikely scenario for this case), the old code took 27.6 seconds, against 24.7 for the new one.

The new utility doesn’t mess with my design, and it performs better. What else could I ask for?  🙂

Advertisements
  1. #1 by RCRD LBL on September 15, 2011 - 12:41 am

    Got a lot out of your excerpt, many thanks.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: