这不应该是有效的C#代码吗?
class A<T> where T : class {
public void DoWork<K>() where K : T {
var b = new B<K>(); // <- compile time error
}
}
class B<U> where U : class {
}
编译器吐出此错误:
错误CS0452:类型“K”必须是引用类型才能在泛型类型或方法“ConsoleApplication1.B”中将其用作参数“U”
编译器是否应该能够确定K是约束为T类型还是从T派生,因此它显然应该是引用类型(T被约束为引用类型)?
答案 0 :(得分:8)
我之前的回答是不正确的;我删除了它。感谢用户配置器指出了我的错误。
编译器是否应该能够确定K是约束为T类型还是从T派生,因此它显然应该是引用类型(T被约束为引用类型)?
没有
K被约束为T类型或从T派生的类型.T被约束为参考类型。 这并不意味着K是引用类型。 Viz:object是引用类型,int是从object派生的类型。如果T是对象,那么K可以是int,这不是引用类型。
答案 1 :(得分:7)
指定type参数时应用约束。虽然为U指定了K,但尚未为K指定类型。由于U要求其类型为引用类型,因此编译器希望确认K确实是引用类型,但它不能。因此,您需要明确说明它将是。
第4.4.4节中的对于每个where子句,将针对每个约束检查与命名类型参数对应的类型参数A ...
以后:
如果给定类型参数不满足一个或多个类型参数的约束,则会发生编译时错误。
由于不继承类型参数,因此也不会继承约束。
最后一点表明K不会从T继承约束。
<强>更新强>
虽然我的结论看似正确,但我的证据有点不稳定,正如Eric Lippert's response现已删除的回复中所阐明的那样。在那里,Eric表示规范的正确部分是:
已知类型参数为a 引用类型,如果它有引用 类型约束或其有效基数 class不是对象或
System.ValueType
。
答案 2 :(得分:3)
约束不会以这种方式级联。每个通用签名都有自己独特的约束,这些约束独立于可能隐含的任何子约束进行评估。您需要在K以及T和U上进行类声明,即使它已经隐含在T中。
答案 3 :(得分:2)
试试这个:
class A<T> where T : class
{
public void DoWork<K>() where K : class, T
{
var b = new B<K>(); // <- compile time error
}
}
class B<U> where U : class
{
}
不幸的是,看起来编译器不够明亮,无法推断。但是,如果你为K添加一些更多的约束,你应该很高兴。
答案 4 :(得分:1)
我认为您需要指定K:class和T.
class A<T> where T : class {
public void DoWork<K>() where K : class, T {
var b = new B<K>(); // <- compile time error
}
}
class B<U> where U : class {
}
答案 5 :(得分:0)
你应该这样做:
class A<T> where T : class
{
public void DoWork<K>() where K: class, T
{
var b = new B<K>(); // <- compile time error
}
}
class B<U> where U : class
{
}
编辑:如果您没有将K指定为类并且具有无参数构造函数,那么您将编译时错误:类型U必须是ref类型,并且需要具有无参数构造函数