对类型参数的约束-new()



根据MSDN,new()约束用于确保类型参数必须具有公共无参数构造函数。但是,请考虑下面给出的示例(取自同一页(。

public class Employee
{
public Employee(string name, int id)
{
Name = name;
ID = id;
}
public string Name { get; set; }
public int ID { get; set; }
}
class EmployeeList<T> where T : Employee, new()
{
}

这里,Employee类型没有无参数/默认构造函数,但此代码编译成功。有人能详细说明一下这个约束的用法以及为什么它有效吗?

编译代码是因为完全可以使用无参数构造函数从Employee派生类型,而约束就是这么说的。约束是而不是试图说Employee本身有一个无参数构造函数,事实上,由于不满足约束,使用EmployeeList<Employee>的尝试将失败。

作为有效的示例:

public class GeneratedEmployee : Employee
{
public GeneratedEmployee() : base(GenerateName(), GenerateId())
{
}
private static string GenerateName()
{
// Implementation here
}
private static int GenerateId()
{
// Implementation here
}
}

此时,可以创建一个EmployeeList<GeneratedEmployee>,并且假设EmployeeList<>类在实现中的某个地方使用new(),它将调用GeneratedEmployee的无参数构造函数。

也就是说,这是一个非常奇怪的约束,因为我不希望你真的想在不指定姓名和ID的情况下创建一名员工。

这里,Employee类型没有无参数/默认构造函数,但此代码成功编译

这是正确的,但是您没有尝试实际使用该类。没有编译的实际上是试图调用EmployeeList<Employee>:

CS0310 'Employee' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'EmployeeList<T>'

正如您正确引用的,Employee与约束T : Employee, new()不匹配。给它提供与之匹配的东西的唯一方法是从Employee派生一个实现默认构造函数的类,并提供它。

您的列表指出该类必须是Employee,或者派生自Employees。Employee本身没有无参数构造函数,因此它将作为类型参数失败:

//fails to compile
var xx = new EmployeeList<Employee>()

但是,如果您定义了一个从Employee继承的类:

public class EmployeeDerived : Employee
{
public EmployeeDerived() : base("test", 123)
{
}
}

这个类确实有一个无参数构造函数(尽管它非常无用(。因此编译器可以将其用作EmployeeList 的T

即使Employee没有无参数构造函数,Employee的子类也可以

public class Manager: Employee {
// these parameters don't make sense - just an example
public EmployeeSubclass(): base("foo", 1) {

}
}

然后我可以使用Manager作为EmployeeList-EmployeeList<Manager>的类型参数。它同时满足两个约束!

class EmployeeList<T> where T : Employee, new()
{
}

T必须是具有无参数构造函数的EmployeeEmployee子代,但Employee没有构造函数并不意味着它的子代不能有。

new()约束将阻止new EmployeeList<Employee>();编译,但您可以执行:

class EmployeeChild : Employee
{
public EmployeeChild() : base("", 1)
{
}
}

这将满足所有约束,并且new EmployeeList<EmployeeChild>();将编译得很好。

最新更新