Why does Generic class signature require specifying new() if type T needs instantiation ?
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 开发者_如何学Goat 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
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
T
s toBar
or types derived fromBar
within the body - let me call public and in-scope internal methods of
Bar
on aT
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.
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.
- With only
Bar
as a constraint,T
can beBar
or any derivative ofBar
, with or without a default constructor. - With only
new()
as a constraint,T
can be any type with a default constructor. - With
Bar
andnew()
as constraints,T
must beBar
or a subclass ofBar
and must also have a default constructor.
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.
Although Bar
may be concrete, the derived class T
could itself be abstract or lack a default constructor.
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.
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.
精彩评论