为什么我不能使用两个泛型类型参数的协方差?

Vin*_*ele 14 c# generics covariance

请考虑以下示例:

class Base {}

class Derived : Base {}

class Test1
{
    private List<Derived> m_X;

    public IEnumerable<Base> GetEnumerable()
    {
        return m_X;
    }
}
Run Code Online (Sandbox Code Playgroud)

编译得很好,因为它IEnumerable<T>协变T.

但是,如果我做同样的事情,但现在使用泛型:

class Test2<TBase, TDerived> where TDerived : TBase
{
    private List<TDerived> m_X;

    public IEnumerable<TBase> GetEnumerable()
    {
        return m_X;
    }
}
Run Code Online (Sandbox Code Playgroud)

我得到编译器错误

无法将表达式类型'System.Collection.Generic.List'转换为返回类型'System.Collection.Generic.IEnumerable'

我在这做错了什么?

Age*_*ire 14

事情是,在第一种情况下,Base已知是一类.在第二种情况下,type参数T可以是类或结构(这是编译器的思考方式).

通过指定T是一个类来解决这个问题,错误将消失:

class Test2<TBase, TDerived> where TDerived : class, TBase
{
    private List<TDerived> m_X;

    public IEnumerable<TBase> GetEnumerable()
    {
        return m_X;
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,编译器试图告诉我们TDerived可能是一个结构(因为你没有指定class约束),而且正如我们 已经知道的那样,协方差和逆变不适用于结构.

  • @roryap你所说的是一个C#规则.在CIL中,此规则不适用(所有C#结构都派生自类).当一个项目建成时,它不再是C#,它是CIL.但您仍然可以使用C#项目中的代码(例如,那些泛型类型).因此,我猜测C#编译器不会假设所有可能的CLI语言都隐式强制执行自己的规则.因此,它需要一个明确的约束. (2认同)