C# 约束泛型类型参数的逆变换

C# 约束泛型类型参数的逆变换,c#,generics,covariance,C#,Generics,Covariance,参考Visual Studio 2010 express中为C#编译的测试代码 public class Test { class Base { } class Derived : Base { } void Test1(IEnumerable<Derived> derived) { IEnumerable<Base> b = derived; //This works fine using covariance on I

参考Visual Studio 2010 express中为C#编译的测试代码

public class Test
{
    class Base { }
    class Derived : Base { }

    void Test1(IEnumerable<Derived> derived)
    {
        IEnumerable<Base> b = derived; //This works fine using covariance on IEnumerable
    }

    void Test2<TDerived, TBase>(TDerived derived) where TDerived : TBase
    {
        TBase b = derived; //This works fine because TDerived is constrained to derive from TBase
    }

    void Test3<TDerived, TBase>(IEnumerable<TDerived> derived) where TDerived : TBase
    {
        IEnumerable<TBase> b = derived; //ERROR: paraphrased: Cannot implicitly convert type IEnumerable<TDerived> to IEnumerable<TBase>
    }
}
公共类测试
{
类基{}
派生类:基{}
void Test1(IEnumerable派生)
{
IEnumerable b=derived;//使用IEnumerable上的协方差可以很好地工作
}
void Test2(TDerived派生),其中TDerived:TBase
{
TBase b=derived;//这很好,因为tderive被约束为从TBase派生
}
void Test3(IEnumerable派生),其中TDerived:TBase
{
IEnumerable b=derived;//错误:转述:无法将类型IEnumerable隐式转换为IEnumerable
}
}
我试图利用IEnumerable的协方差将泛型类型参数的可枚举项存储在该类型参数被约束从中继承的类的可枚举项中。Test3就是一个例子。注意,Test1和Test2(分别演示编译时类型的协方差和受约束类型的赋值)都可以很好地编译。这两种语言功能的结合对我来说并不适用


我能够使用
IEnumerable b=derived.Cast()
,并且100%相信,如果我的理解没有缺陷,任何转换都不会失败,因此我确实有一个解决方法。我的问题是,为什么编译器不允许这样做?这是出于某种逻辑原因、编译器的疏忽还是我没有想到的其他原因而被禁止的?

回答最初的问题

您当前正在尝试将类型为
TDerived
的单个元素转换为类型为
Base
的序列。我也不希望您的
Cast
调用起作用,因为
TDerived
没有实现
IEnumerable
——我怀疑您实际上已经在不同的情况下使用了它

我猜你的意思是:


你完全正确。然而,我实际上犯了那个错误,试图把我的问题归结为最简单的形式。我已经修改了我的问题,以反映更复杂的情况,这对我来说仍然是失败的。在这种情况下,基类和派生类都是泛型类型参数。@ShaneTapp:这就是为什么在提问时要小心的原因,这样你就不会浪费人们的时间。(不仅仅是我,还有所有在编辑前看问题的人。)我编辑了我的答案以反映问题的变化。乔恩·斯基特已经给出了答案
IEnumerable
是协变的,但协变仅适用于C#中的引用类型。例如,如果
der
IEnumerable
,则赋值
IEnumerable b=der将不被允许。So
Test3(der)将是一个问题,即使
int
IFormattable
void Test3<TDerived>(IEnumerable<TDerived> derived) where TDerived : Base
{
    IEnumerable<Base> b = derived;
}
void Test3<TDerived, TBase>(IEnumerable<TDerived> derived)
    where TDerived : class, TBase
{
    IEnumerable<TBase> b = derived;
}