我正在写一个Generic类,如下所示。
public class Foo<T> :
where T : Bar, new()
{
public void MethodInFoo()
{
T _t = new T();
}
}
正如您所看到的,T类型的对象_t
在运行时被实例化。为了支持泛型类型T的实例化,语言强制我将new()放在类签名中。如果Bar是一个抽象类,我同意这个,但是如果使用公共无参数构造函数的Bar标准非抽象类,为什么需要这样呢。
如果找不到new(),编译器将提示以下消息。
无法创建变量类型'T'的实例,因为它没有new()约束
答案 0 :(得分:22)
因为通常不会假设模板参数需要[非抽象且可构造] [通过公共无参数构造函数]才能使Type与模板参数定义匹配。
在模板上添加:new()
约束之前:
T
T
与抽象类型或类型匹配,而不使用公共无参数构造函数 :Bar
位是正交的,表示:
Bar
T
转换为Bar
或来自Bar
内部的类型Bar
T
的公开和范围内部方法
答案 1 :(得分:11)
仅仅因为Bar
类定义了无参数构造函数,并不意味着Bar
的所有内容都会这样做 - 可能会有一个继承自Bar
的类但隐藏无参数构造函数。这样的类符合Bar
约束,但正确地使new()
约束失败。
(请注意,如果您使Bar
sealed
避免这种可能性,您可以(可以理解)不再将其用作通用约束条件 - 编辑尝试此操作编译器错误CS0701。
答案 2 :(得分:3)
也许是因为如果你不包含new()
约束,那么T
可以合法地成为Bar
的子类,没有默认(即公共和无参数)构造函数,在这种情况下1}}语句中的new T()
语句无效。
Bar
作为约束,T
可以是Bar
或Bar
的任何衍生产品,无论是否有默认构造函数。new()
作为约束,T
可以是具有默认构造函数的任何类型。Bar
和new()
为约束,T
必须是Bar
或Bar
的子类,并且还必须有默认构造函数。答案 3 :(得分:2)
因为Bar的子类可能没有no-arg构造函数。
where T : Bar
表示Bar或Bar的子类。如果你只想要一个Bar实例,你就不会使用泛型。有很多实例(例如Object和String),其中超类具有no-arg构造函数,而子类则没有。
答案 4 :(得分:1)
虽然Bar
可能具体,但派生类T
本身可能是抽象的或缺少默认构造函数。
答案 5 :(得分:1)
您可能已经使用了Bar构造函数:
T _t = new Bar();
没有new()
约束。但是,您使用了T
构造函数,编译器不能也不会假设在添加new()约束之前构造绑定到T的类型。
答案 6 :(得分:0)
对于那些不确定的人,请记住你可以使用
where T : IDeviceCommand
要求T实现某些接口作为最低合同要求。您可以将上述内容描述为“如果提供的类型'T'至少可以打电话给我,则实现IDeviceCommand接口”。当然,这允许您对“T”为您提供操作方法的设施做出一系列(正确的)假设。