13
votes

I'm writing a Generic class as follows.

public class Foo<T> : 
    where T : Bar, new()
{
    public void MethodInFoo()
    {
        T _t = new T();
    }
}

As you can see the object _t of type T is instantiated at runtime. To support instantiation of generic type T, the language forces me to put new() in the class signature. I'd agree to this if Bar is an abstract class but why does it need to be so if Bar standard non-abstract class with public parameterless constructor.

The compiler prompts with the following message if new() is not found.

Cannot create an instance of the variable type 'T' because it does not have the new() constraint

7
thanks to all for your answers. content of the answer was really good for brain-storming on the question topic.this. __curious_geek

7 Answers

22
votes

Because there isn't normally an assumption that the template parameter needs to be [non-abstract and] constructible [via a public parameterless constructor] in order for a Type to match the template parameter definition.

Until you add a :new() constraint on the template:

  • The compiler won't let you construct a T
  • The compiler will let you match T with abstract types or types without a public parameterless constructor

The :Bar bit is orthogonal and means:

  • Don't let people match against types that aren't derived from [or are] Bar
  • Let me cast Ts to Bar or types derived from Bar within the body
  • let me call public and in-scope internal methods of Bar on a T
11
votes

Just because the Bar class defines a parameter-less constructor, doesn't mean that everything that is a Bar will do so - there may be a class that inherits from Bar but hides the parameter-less constructor. Such a class would meet the Bar constraint but rightly fail the new() constraint.

(Note that if you make Bar sealed to avoid this possibility, you can (understandably) no longer use it as a generic constraint) - edit attempting this produces compiler error CS0701.

3
votes

Maybe because if you don't include the new() constraint then T could legitimately be a subclass of Bar with no default (ie, public and parameterless) constructor, in which case the new T() statement inside the method would be invalid.

  1. With only Bar as a constraint, T can be Bar or any derivative of Bar, with or without a default constructor.
  2. With only new() as a constraint, T can be any type with a default constructor.
  3. With Bar and new() as constraints, T must be Bar or a subclass of Bar and must also have a default constructor.
2
votes

Because subclasses of Bar might not have an no-arg constructor.

where T : Bar

indicates Bar, or a subclass of Bar. If you just wanted an instance of Bar, you wouldn't use generics. There are plenty of instances (Object and String, for example) where the superclass has a no-arg constructor, and a subclass does not.

1
votes

Although Bar may be concrete, the derived class T could itself be abstract or lack a default constructor.

1
votes

You could probably have use the Bar constructor:

T _t = new Bar();

without having the new() constraint. However, you used the T constructor and the compiler can not and does not assume that constructing the type that gets bound to T is possible until you add a new() constraint.

0
votes

For those not sure, remember you can use the

where T : IDeviceCommand

to require that T implements some interface as a minimum contractual requirement. Your could verbalize the above as "You can call me if the supplied Type 'T' at a minimum, implements the IDeviceCommand interface". This of course, allows you to make a series of (correct) assumptions of what facilities that 'T' provides your method to operate on.