23

In C# generics, we can declare a constraint for a type parameter T to have a default constructor, by saying where T : new(). However, no other kinds of constraints like this are valid - new(string) for example, etc.

From a language design and/or implementation perspective, what is the reason for this?

Is there something in the way constructors work or in the way the type system is implemented that forbids this (or at least makes it harder)? If so, what is it? I recall reading somewhere that default(T) actually compiles to new T() for T : struct. Is it related to this, maybe?

Or is it simply a design decision made in order to avoid making the language too complicated?

2 Answers2

17

Decompiling (as per Robert Harvey's suggestion) yielded the following, for anyone interested. This method:

static T GenericMake<T>()
    where T : new()
{
    return new T();
}

Apparently, when compiled, becomes this:

private static T GenericMake<T>()
    where T : new()
{
    T t;
    T t1 = default(T);
    if (t1 == null)
    {
        t = Activator.CreateInstance<T>();
    }
    else
    {
        t1 = default(T);
        t = t1;
    }
    return t;
}
  • If T is a value type, new() becomes default(T).
  • If T is a reference type, new() works using reflection. Activator.CreateInstance() internally calls RuntimeType.CreateInstanceDefaultCtor().

So there it is - internally, default constructors really are special to C# in relation to the CLR. Giving other constructors the same treatment would have been costly, even if there are some valid use cases for more complicated constraints in generics.

7

For an authoritative answer, I would refer you to Eric Lippert's answer to that question on StackOverflow a few years ago, a snippet of which is briefly quoted below.

However, in this specific case I can certainly give you some reasons why I would push back on the feature if it came up in a design meeting as a possible feature for a future version of the language.

...

I say that we should either do the whole feature or don't do it at all. If it is important to be able to restrict types to have particular constructors, then let's do the whole feature and restrict types on the basis of members in general and not just constructors.

Chris Hannon
  • 194
  • 4