【问题标题】:C# covariance and inheritanceC#协变和继承
【发布时间】:2013-08-05 16:19:06
【问题描述】:

我很想知道为什么我的接口在抽象基类中的实现不满足子类的要求。这是一个例子:

public interface IBase { }
public interface IConcrete : IBase { }

public interface IBaseManager<out T>
    where T : IBase
{
    T Create();
    IEnumerable<T> SelectAll();
}

public interface IConcreteManager : IBaseManager<IConcrete> { }

public abstract class Base : IBase { }

public class Concrete1 : Base, IConcrete { }

public abstract class BaseManager<T> : IBaseManager<T> where T : class, IBase
{
    #region IBaseManager<T> Members

    public T Create()
    {
        throw new NotImplementedException();
    }

    public IEnumerable<T> SelectAll()
    {
        throw new NotImplementedException();
    }

    #endregion
}

public class ConcreteManager : BaseManager<Concrete>, IConcereteManager
{
             //error occurs here
} 

这是正在生成的错误:

“ConsoleApplication4.ConcreteManager”没有实现接口成员“ConsoleApplication4.IBaseManager.Create()”。

“ConsoleApplication4.BaseManager.Create()”无法实现“ConsoleApplication4.IBaseManager.Create()”,因为它没有匹配的返回类型“ConsoleApplication4.IConcrete”。

如果我将这些方法添加到 ConcreteManager 类中,一切都很好,编译器也很高兴。

public new IConcrete Create()
{
    return base.Create();
}

public new IEnumerable<IConcrete> SelectAll()
{
    return base.SelectAll();
}

如果简单地返回基类返回的方法就足够了,为什么还要添加方法呢?为什么编译器不能调用基类中的方法?

【问题讨论】:

  • 我希望扩展接口是问题,尝试删除它。
  • 你不想public class ConcreteManager : BaseManager&lt;IConcrete&gt;, IConcereteManager 吗?

标签: c# inheritance covariance


【解决方案1】:

正如 John 正确指出的那样,C# 语言不支持返回类型协变。 CLR 也不支持,因此即使语言支持它,我们真正实现该功能的唯一方法是静默生成您必须自己添加的代码。

避免编写这些存根方法给开发人员带来的小小好处并不能证明执行更通用的协方差功能需要付出可观的成本,因此我们从未这样做过。

【讨论】:

  • 那么说协方差实际上是对返回值的赋值准确吗?
  • @Seattle Leonard:我不明白这个问题。协方差是映射保留关系方向的属性。在返回类型协方差的情况下,我们有两个关系:赋值兼容性和虚拟槽兼容性。在从类型到返回这些类型的方法的映射相对于这些关系是“协变”的语言中,如果 X 与 Y 赋值兼容,则返回 X 的方法与返回 Y 的方法。
  • @EricLippert 我不会说协变返回类型对开发人员来说是一个小小的好处。在我最新的项目中,我添加了多达一百个这样的“不变修复”。还是我总体上做错了什么?
  • 使用IOtherInterface 方法/属性实现IMyInterface 以获得更好的概览MyClass 使用OtherClass(派生自IOtherInterface)方法/属性,我总是需要这样的修复.
【解决方案2】:

看起来您假设返回类型为协方差,因为 ConcreteManager(作为 IConcreteManager)期望 Create()SelectAll() 方法的返回类型分别为 IConcreteIEnumerable&lt;IConcrete&gt;,其中基类不提供。

您收到这些错误是因为 C# 不支持返回类型协方差。

【讨论】:

    【解决方案3】:

    当你实现一个接口/抽象类时,你必须使用相同的签名。 See here

    不要让泛型让你失望,这与没有泛型没有什么不同。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-09
      • 1970-01-01
      • 2017-10-21
      相关资源
      最近更新 更多