如果类型T需要实例化,为什么泛型类签名需要指定new()?

时间:2009-12-03 13:03:56

标签: c# generics

我正在写一个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()约束

7 个答案:

答案 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的子类,没有默认(即公共和无参数)构造函数,在这种情况下new T()语句无效。

  1. 只有Bar作为约束,T可以是BarBar的任何衍生产品,无论是否有默认构造函数。
  2. new()作为约束,T可以是具有默认构造函数的任何类型。
  3. Barnew()为约束,T必须是BarBar的子类,并且还必须有默认构造函数。

答案 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”为您提供操作方法的设施做出一系列(正确的)假设。