当前位置: 首页 > 面试题库 >

返回派生类型时,“未实现接口”

武晨
2023-03-14
问题内容

如下代码:

public interface ISomeData
{
    IEnumerable<string> Data { get; }
}

public class MyData : ISomeData
{
    private List<string> m_MyData = new List<string>();
    public List<string> Data { get { return m_MyData; } }
}

产生以下错误:

错误CS0738:“ InheritanceTest.MyData”未实现接口成员“
InheritanceTest.ISomeData.Data”。’InheritanceTest.MyData.Data’无法实现’InheritanceTest.ISomeData.Data’,因为它没有匹配的返回类型’System.Collections.Generic.IEnumerable’。

由于List 实现IEnumerable ,因此人们会认为我的类将实现该接口。有人可以解释不进行编译的基本原理吗?

如我所见,有两种可能的解决方案:

  1. 将接口更改为更具体,并要求实现IList。
  2. 更改我的类(MyData)以返回IEnumerable并实现原始接口。

现在假设我还有以下代码:

public class ConsumerA
{
    static void IterateOverCollection(ISomeData data)
    {
        foreach (string prop in data.MyData)
        {
            /*do stuff*/
        }
    }
}

public class ConsumerB
{
    static void RandomAccess(MyData data)
    {

        data.Data[1] = "this line is invalid if MyPropList return an IEnumerable<string>";
    }
}

我可以更改接口以要求实现IList(选项1),但这限制了可以实现该接口的人员以及可以传递给ConsumerA的类的数量。或者,我可以更改实现(类MyData),以便它返回IEnumerable而不是列表(选项2),但随后必须重写ConsumerB。

除非有人能启发我,否则这似乎是C#的缺点。


问题答案:

不幸的是,返回类型必须匹配。您正在寻找的被称为“返回类型协方差”,而C#不支持。

http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=90909

C#编译器团队的高级开发人员Eric Lippert在他的博客中提到,他们不打算支持返回类型协方差。

“这种差异称为“返回类型协方差”。正如我在本系列文章的前面部分提到的那样,(a)该系列与这种差异无关,并且(b)我们没有计划在C#。 ”

http://blogs.msdn.com/ericlippert/archive/2008/05/07/covariance-and-
contravariance-part-twelve-to-infinity-but-not-
beyond.aspx

值得阅读Eric关于协方差和相反方差的文章。

http://blogs.msdn.com/ericlippert/archive/tags/Covariance+and+Contravariance/default.aspx



 类似资料:
  • 我可以写: 但这当然不起作用,因为调用返回的是而不是我想要的。 我可以通过在(以及和等)中键入类型并抑制警告来避免这个问题,但是即使只有(比方说)10个扩展的实体类,这仍然是为了键入而编写的样板代码。此外,我认为,如果我必须为每个派生类编写代码(无论多么小)(也会有其他类似的方法),那么拥有类层次结构的好处就会丧失很多。 对此有更好的解决方案吗? 更新:使用Java7。

  • 问题内容: 如何在实现类中强制执行方法getFoo(),返回相同实现类类型的列表。 现在,实现Bar的类将返回实现Bar的任何类的对象。我想使其更加严格,以便实现Bar的类在getFoo()中仅返回其类型的对象列表。 问题答案: 不幸的是,这不能由Java的类型系统强制执行。 但是,您可以通过使用以下方法来达到非常接近的效果: 然后您的实现类可以像这样实现它: 但是没有什么可以阻止另一个类这样做:

  • 好吧,乖点。 这里有一个枚举,它实现了一个接口,该接口返回一个“原始类型”,它给我一个关于接口中的方法的警告。 如果我将接口的方法更改为: 它会在的方法签名上变为未经检查的警告。如果我改变的签名: 然后返回有一个不兼容的类型错误,因为

  • 我正在学习一本书,即“.NET域驱动的C#设计”。 问题基于如下类图所示的场景: 图:http://screencast.com/t/a9uuljvw0 现在,如果我用ICompanyRepository变量comrep调用Add()函数... 然后调用RepositoryBase类(它是CompanyRepository的父类)中的Add()函数。 我的问题是:在(抽象基)类“repositor

  • 数据结构是指若干个数据的连接方式,一个复杂的数据往往是由若干个不同类型数据形成的结构。派生类型是指用户利用FORTRAN系统内部类型,如数值型、逻辑型、字符型等自行设计出一个新的数据类型,它们实际上是由内部类型数据形成的某种结构。本章主要目的是学会按复杂数据的客观结构形态,由程序员定义出一种派生类型,再结合上将在后面叙述的模块后,可将该类型必需的操作写成内部子程序,连同派生类型一起写在模块中,供程