简体   繁体   English

约束泛型类型参数的逆解

[英]Contravariance on constrained generic type parameters

Referring to this test code compiled for C# in Visual Studio 2010 express 参考在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>
    }
}

I am attempting to utilize the covariance of IEnumerable to store an enumerable of a generic type parameter within an enumerable of a class that that type parameter is constrained to inherit from. 我试图利用IEnumerable的协方差将一个泛型类型参数的可枚举存储在该类型参数被约束为继承的类的可枚举中。 This is exemplified by Test3. 这由Test3举例说明。 Note that Test1 and Test2 (demonstrating covariance on compile time types and assignment of constrained types respectively) both compile fine. 请注意,Test1和Test2(分别演示编译时类型的协方差和约束类型的赋值)都可以正常编译。 It is the combination of the two language features which isn't working for me. 它是两种语言功能的组合,对我来说不起作用。

I am able to use IEnumerable<TBase> b = derived.Cast<TBase>() and be 100% confident that no cast will fail if my understanding is not flawed so I do have a workaround available. 我能够使用IEnumerable<TBase> b = derived.Cast<TBase>()并且100%确信如果我的理解没有缺陷,任何演员都不会失败,所以我确实有一个可用的解决方法。 My question is, why does the compiler not allow this? 我的问题是,为什么编译器不允许这样做? Is this forbidden for some logical reason, an oversight in the compiler, or something else I haven't thought of? 出于某些逻辑原因,编译器中的疏忽或其他我没有想到的其他原因,这是否被禁止?

Answer to initial question 回答最初的问题

You're currently trying to convert a single element of type TDerived to a sequence of type Base . 您当前正在尝试将TDerived类型的单个元素转换为Base类型的序列 I wouldn't expect your Cast call to work either, as TDerived doesn't implement IEnumerable - I suspect you've actually got that to work in a different situation instead. 我不希望你的Cast调用工作,因为TDerived没有实现IEnumerable - 我怀疑你实际上已经TDerived在不同的情况下工作了。

I suspect you actually meant: 我怀疑你实际上意味着:

void Test3<TDerived>(IEnumerable<TDerived> derived) where TDerived : Base
{
    IEnumerable<Base> b = derived;
}

That compiles with no problems. 这没有任何问题。

Answer to edited question 回答编辑过的问题

Okay, now we've got the real problem between two type parameters, the issue is that the compiler doesn't know that they're reference types - which is required for generic variance. 好的,现在我们在两个类型参数之间遇到了真正的问题,问题是编译器不知道它们是引用类型 - 这是泛型方差所必需的。 You can fix that with a class constraint on TDerived : 您可以使用TDerived上的class约束来修复它:

void Test3<TDerived, TBase>(IEnumerable<TDerived> derived)
    where TDerived : class, TBase
{
    IEnumerable<TBase> b = derived;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM