开发者

Why does Generic class signature require specifying new() if type T needs instantiation ?

开发者 https://www.devze.com 2022-12-13 15:42 出处:网络
I\'m writing a Generic class as follows. public class Foo<T> : where T : Bar, new() { public void MethodInFoo()

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 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


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.

  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.


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消