约束泛型类型参数的逆解

Sha*_*app 2 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 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>
    }
}
Run Code Online (Sandbox Code Playgroud)

我试图利用IEnumerable的协方差将一个泛型类型参数的可枚举存储在该类型参数被约束为继承的类的可枚举中.这由Test3举例说明.请注意,Test1和Test2(分别演示编译时类型的协方差和约束类型的赋值)都可以正常编译.它是两种语言功能的组合,对我来说不起作用.

IEnumerable<TBase> b = derived.Cast<TBase>()如果我的理解没有缺陷,我可以使用并且100%确信没有演员会失败,所以我确实有一个可用的解决方法.我的问题是,为什么编译器不允许这样做?这是出于某些逻辑原因,编译器中的疏忽或者其他我没有想到的其他原因而被禁止的吗?

Jon*_*eet 10

回答最初的问题

您目前正在尝试转换成一个单一类型的元素TDerived序列类型Base.我不希望你的Cast电话工作,TDerived也没有实现IEnumerable- 我怀疑你实际上已经让它在不同的情况下工作.

我怀疑你真正的意思是:

void Test3<TDerived>(IEnumerable<TDerived> derived) where TDerived : Base
{
    IEnumerable<Base> b = derived;
}
Run Code Online (Sandbox Code Playgroud)

这没有任何问题.

回答编辑过的问题

好的,现在我们在两个类型参数之间遇到了真正的问题,问题是编译器不知道它们是引用类型 - 这是泛型方差所必需的.您可以通过以下class约束来解决此问题TDerived:

void Test3<TDerived, TBase>(IEnumerable<TDerived> derived)
    where TDerived : class, TBase
{
    IEnumerable<TBase> b = derived;
}
Run Code Online (Sandbox Code Playgroud)