“where T : class, new()”是什么意思?

390
你能解释一下以下代码中的 where T : class, new() 是什么意思吗?
void Add<T>(T item) where T : class, new();

13
请将此链接保存以备后用:http://msdn.microsoft.com/zh-cn/library/d5x73970.aspx - Ahmet Kakıcı
这个回答解决了你的问题吗?new() 是什么意思? - Heretic Monkey
11个回答

422
这是对泛型参数 T 的限制。它必须是一个 class(引用类型),并且必须有一个公共的无参默认构造函数。
这意味着 T 不能是 intfloatdoubleDateTime 或任何其他的 struct(值类型)。
它可以是一个 string,或任何其他自定义的引用类型,只要它有一个默认或无参构造函数。

6
需要翻译的内容:Just to clarify, if you don't have the class clause as part of the where T..., then it is safe to use int, float, double etc.如果你在 where T... 子句中没有添加 class,那么使用 int、float、double 等类型是安全的。 - AboutDev
1
@AboutDev 正确,您不必对通用类型参数设置约束。但是,如果您创建的通用类型只希望在引用类型或值类型上工作,则应该指定。没有约束,您可以期望引用类型(类)或值类型(结构体(int、float、double ...))。 - NerdFury
1
T : [interface name], new() 这种情况下呢?你还需要一个无参构造函数吗? - Vince Tino
3
为了澄清Justin的评论,一个空构造函数没有语句(就像默认构造函数一样),而一个无参构造函数可能包含语句(比如初始化列表)。 - DharmaTurtle
@VinceTino:new() 精确指定“必须有一个公共的无参数构造函数”。 - Flater
令我感到惊讶的是,new() 也会排除只有一个参数和默认值的构造函数... 我觉得这很不直观。 - mBardos

215

这些是通用类型约束。在您的情况下,有两个约束:

where T : class

这意味着类型T必须是引用类型(而不是值类型)。

where T : new()

意味着类型T必须具有无参数构造函数。有此约束将允许您在代码中执行T field = new T();等操作,否则您将无法执行此操作。

然后使用逗号将两者组合起来,得到:

where T : class, new()

第二和第三点都很好,只是补充一下,我认为第二点在使用泛型类型进行反射时非常有用。例如:T t = new T(); t.GetType().GetProperty("ID").SetValue(t, uniqueId, null); - OKEEngine
1
我认为在声明 where T : class, new() 时加上 class 是多余的,因为 new() 已经隐含了 class 的意思,而结构体无法有默认构造函数。 - DharmaTurtle
1
@DharmaTurtle,“结构体不能包含显式的无参数构造函数”,并不意味着它们没有,而是说你不能定义一个这样的构造函数。来源:https://msdn.microsoft.com/tr-tr/library/aa288208(v=vs.71).aspx - rustem

159

where T : struct

类型参数必须是值类型。除了 Nullable 类型之外,任何值类型都可以指定。有关更多信息,请参阅使用可空类型 (C# 编程指南)。

where T : class

类型参数必须是引用类型,包括任何类、接口、委托或数组类型。(请参见下面的说明。)

where T : new()

类型参数必须具有公共的无参数构造函数。当与其他约束一起使用时,new() 约束必须最后指定。

where T : [base class name]

类型参数必须是指定基类或从指定基类派生的类。

where T : [interface name]

类型参数必须实现指定的接口或从指定的接口派生。可以指定多个接口约束。约束接口也可以是泛型的。

where T : U

T 提供的类型参数必须是 U 提供的参数或从其派生的类型。这称为裸类型约束。

(原始来源:https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters)


28
这很有用,但是链接到来源 - Skean

37

classnew是对泛型类型参数T的两个约束条件。它们分别确保:

class

类型参数必须是引用类型;这也适用于任何类、接口、委托或数组类型。

new

类型参数必须具有公共的无参构造函数。当与其他约束一起使用时,必须将new()约束指定为最后一个。

它们的组合意味着类型T必须是引用类型(不能是值类型),并且必须具有无参构造函数。

示例:

struct MyStruct { } // structs are value types

class MyClass1 { } // no constructors defined, so the class implicitly has a parameterless one

class MyClass2 // parameterless constructor explicitly defined
{
    public MyClass2() { }
}

class MyClass3 // only non-parameterless constructor defined
{
    public MyClass3(object parameter) { }
}

class MyClass4 // both parameterless & non-parameterless constructors defined
{
    public MyClass4() { }
    public MyClass4(object parameter) { }
}

interface INewable<T>
    where T : new()
{
}

interface INewableReference<T>
    where T : class, new()
{
}

class Checks
{
    INewable<int> cn1; // ALLOWED: has parameterless ctor
    INewable<string> n2; // NOT ALLOWED: no parameterless ctor
    INewable<MyStruct> n3; // ALLOWED: has parameterless ctor
    INewable<MyClass1> n4; // ALLOWED: has parameterless ctor
    INewable<MyClass2> n5; // ALLOWED: has parameterless ctor
    INewable<MyClass3> n6; // NOT ALLOWED: no parameterless ctor
    INewable<MyClass4> n7; // ALLOWED: has parameterless ctor

    INewableReference<int> nr1; // NOT ALLOWED: not a reference type
    INewableReference<string> nr2; // NOT ALLOWED: no parameterless ctor
    INewableReference<MyStruct> nr3; // NOT ALLOWED: not a reference type
    INewableReference<MyClass1> nr4; // ALLOWED: has parameterless ctor
    INewableReference<MyClass2> nr5; // ALLOWED: has parameterless ctor
    INewableReference<MyClass3> nr6; // NOT ALLOWED: no parameterless ctor
    INewableReference<MyClass4> nr7; // ALLOWED: has parameterless ctor
}

1
好的演示。谢谢。 - Subhan Ali

17

new(): 使用new()约束意味着类型T必须使用无参数构造函数,因此可以从中实例化对象 - 请参见默认构造函数

class: 表示T必须是引用类型,因此它不能是int、float、double、DateTime或其他结构(值类型)。

public void MakeCars()
{
    //This won't compile as researchEngine doesn't have a public constructor and so can't be instantiated.
    CarFactory<ResearchEngine> researchLine = new CarFactory<ResearchEngine>();
    var researchEngine = researchLine.MakeEngine();

    //Can instantiate new object of class with default public constructor
    CarFactory<ProductionEngine> productionLine = new CarFactory<ProductionEngine>();
    var productionEngine = productionLine.MakeEngine();
}

public class ProductionEngine { }
public class ResearchEngine
{
    private ResearchEngine() { }
}

public class CarFactory<TEngine> where TEngine : class, new()
{
    public TEngine MakeEngine()
    {
        return new TEngine();
    }
}

6

这意味着类型T必须是一个类,并且具有不需要任何参数的构造函数。

例如,您必须能够执行以下操作:

T t = new T();

1
不仅仅是一个构造函数,而是一个不带参数的构造函数。 - NerdFury
@NerdFury:谢谢。那是一个重要的部分。已经更正。 - Evan Mulawski

6

where (C# Reference)

new() 约束让编译器知道任何提供的类型参数必须具有可访问的无参或默认构造函数。

因此,应该是,T 必须是一个类,并且具有可访问的无参或默认构造函数。


5

"Where"后面的内容是对您声明的泛型类型T的限制,因此:

  • class表示T应该是一个类而不是值类型或结构体。

  • new()表示T类应该定义公共无参默认构造函数。


2

这被称为对泛型参数T的“约束”。它意味着T必须是引用类型(一个类),并且它必须具有公共默认构造函数。


1
这是泛型机制的一部分,其中where关键字添加了约束条件,以确定哪些类型必须实现才能用作类型参数。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接