C#泛型类型约束

时间:2011-02-18 13:40:41

标签: c# generics

这不应该是有效的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被约束为引用类型)?

6 个答案:

答案 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节中的

The specification州:

  

对于每个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类型,并且需要具有无参数构造函数