C#generics类型约束

这不应该是有效的C#代码吗?

class A where T : class { public void DoWork() where K : T { var b = new B(); // <- compile time error } } class B where U : class { } 

编译器吐出此错误:

错误CS0452:类型“K”必须是引用类型才能在generics类型或方法“ConsoleApplication1.B”中将其用作参数“U”

编译器是否应该能够确定K是约束为T类型还是从T派生,因此它显然应该是引用类型(T被约束为引用类型)?

指定type参数时将应用约束。 虽然为U指定了K,但尚未为K指定类型。由于U要求其类型为引用类型,编译器希望确认K确实是引用类型,但它不能。 因此,您需要明确声明它将是。

规范在4.4.4节中说明:

对于每个where子句,将针对每个约束检查与命名类型参数对应的类型参数A.

然后:

如果给定类型参数不满足一个或多个类型参数的约束,则会发生编译时错误。

由于不inheritance类型参数,因此也不会inheritance约束。

最后一点表明K不会inheritanceT的约束。

更新
虽然我的结论看起来是正确的,但我的证据有点不稳定,正如Eric Lippert回应中现在删除的回复中所阐明的那样。 在那里,Eric表示规范的正确部分是:

如果类型参数具有引用类型约束或其有效基类不是对象或System.ValueType则已知类型参数是引用类型。

我之前的回答是不正确的; 我删除了它。 感谢用户配置器指出我的错误。

编译器是否应该能够确定K是约束为T类型还是从T派生,因此它显然应该是引用类型(T被约束为引用类型)?

没有。

K被约束为T型或从T派生的类型.T被约束为参考类型。 这并不意味着K是参考类型。 Viz:object是引用类型,int是从object派生的类型。 如果T是object,则K可以是int,这不是引用类型。

约束不以这种方式级联。 每个通用签名都有自己独特的约束,这些约束独立于可能隐含的任何子约束进行评估。 你需要在K以及T和U上进行类声明,即使它已经暗示了T.

试试这个:

 class A where T : class { public void DoWork() where K : class, T { var b = new B(); // <- compile time error } } class B where U : class { } 

不幸的是,看起来编译器不够明亮,无法推断。 但是,如果你为K添加更多约束,你应该好好去。

我想你需要指定K:class和T.

 class A where T : class { public void DoWork() where K : class, T { var b = new B(); // <- compile time error } } class B where U : class { } 

你应该做这个 :

 class A where T : class { public void DoWork() where K: class, T { var b = new B(); // <- compile time error } } class B where U : class { } 

编辑:如果您没有将K指定为类并且具有无参数构造函数,那么您将编译时错误:类型U必须是ref类型,并且需要具有无参数构造函数