【问题标题】:interface covariance issue接口协方差问题
【发布时间】:2011-06-08 22:46:58
【问题描述】:

以下代码示例:

interface I<out T>
    where T : class, I<T>
{
    T GetT();
}

interface J : I<J>
{
}

abstract class B<T> : I<T>
    where T : B<T>
{
    T I<T>.GetT()
    {
        return null;
    }
}

class C : B<C>, J
{
}

编译失败(在带有 SP1 的 VS2010 下)并出现以下错误:

Error   4   'C' does not implement interface member 'I<J>.GetT()'

但是,C 确实实现了(通过其基 B)I,由于 I 被声明为协变,它也应该捕获 I(如 C : J)。

这是编译器错误吗?如果不是,为什么我不允许这样做?

【问题讨论】:

  • 怀疑这可能是由于显式接口实现。您是否尝试过将B&lt;T&gt;.GetT() 公开?
  • 是的,我有。错误仍然存​​在,并添加了 B 的实现具有无效返回类型以匹配的注释(我们没有返回类型协方差)。

标签: c#-4.0 covariance


【解决方案1】:

即使它是协变的,你不能改变接口的返回类型。这与非泛型类中的协方差没有什么不同。

interface Animal
{
    Animal GetAnimal();
}

class Cat : Animal
{
   //Not ALlowed
   Cat GetAnimal()
   {
       return this;
   }

   //Allowed
   Animal GetAnimal()
   {
       return this;
   }   
}

问题是 C 作为 B&lt;C&gt; 的特化返回 C I&lt;C&gt;.GetT(),但是 J 的规范需要 J GetT()

尝试以下方法:

interface I<out T>
    where T : class, I<T>
{
    T GetT();
}

interface J : I<J>
{
}

abstract class B<T,U> : I<U>
    where T : B<T,U>, U
    where U : class, I<U>
{
    U I<U>.GetT()
    {
        return null;
    }
}

class C : B<C,J>, J
{
}

【讨论】:

  • 看来,方差仅“从外部”有用 - 这里 I&lt;C&gt;可转换I&lt;J&gt;,前者的实现是 不是 后者的实现。我说的对吗?
  • @Grzegorz,你在问另一个问题。代码无法编译的原因与协方差无关,它与 CLR 语言不允许您在实现中修改接口方法的签名这一事实有关——即使它是一个约束。就个人而言,我发现泛型的协变特性在处理泛型集合时最有用。即IList&lt;B&gt; bList = new IList&lt;C&gt;(){};(其中 C : B)。
  • @Ethan:编译正确:interface I&lt;out T&gt; { T GetT(); } class A { } class B : A { } class C : I&lt;B&gt; { B I&lt;B&gt;.GetT() { return null; } static void M() { I&lt;A&gt; ia = new C(); } }。这里,I&lt;B&gt; 的实现(自动)充当I&lt;A&gt; 的实现,即使GetT 的返回类型不同。目前尚不清楚(至少对我而言)为什么它不应该在原始情况下工作。而且,顺便说一句,IIRC IList 不是协变的......
  • 此外,如果我在I&lt;B&gt; 旁边添加I&lt;A&gt;,代码将无法编译——即使编译器非常乐意将C 类的对象视为I&lt;A&gt;,直到我明确表示它是一个!
  • 这似乎不是编译器问题 - 在上述所有示例中,mono-2.10.2 的行为与 VS 完全相同。
猜你喜欢
  • 2011-10-22
  • 1970-01-01
  • 2013-01-23
  • 2013-08-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多