【问题标题】:Contravariance on constrained generic type parameters受约束的泛型类型参数的逆变
【发布时间】:2013-08-24 19:07:19
【问题描述】:

参考这个在 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>
    }
}

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

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

【问题讨论】:

  • Jon Skeet 已经给出了答案。 IEnumerable&lt;out T&gt; 协变的,但协变仅适用于 C# 中的引用类型。例如,如果derIEnumerable&lt;int&gt;,则不允许分配IEnumerable&lt;IFormattable&gt; b = der;。所以Test3&lt;int, IFormattable&gt;(der); 会是个问题,即使intIFormattable

标签: c# generics covariance


【解决方案1】:

回答最初的问题

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

我怀疑你实际上的意思是:

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

编译没有问题。

对已编辑问题的回答

好的,现在我们解决了两个类型参数之间的real 问题,问题是编译器不知道它们是引用类型——这是泛型变化所必需的。您可以使用TDerived 上的class 约束来解决此问题:

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

【讨论】:

  • 你是绝对正确的。然而,我实际上犯了这个错误,试图将我的问题归结为最简单的形式。我已经修改了我的问题,以反映对我来说仍然失败的更复杂的案例。这是基类和派生类都是泛型类型参数的情况。
  • @ShaneTapp:这就是为什么在提问时要小心谨慎,以免浪费别人的时间。 (不仅是我,还有其他在编辑前查看问题的人。)我已经编辑了我的答案以反映问题的变化。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多