首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >接口实现上成员的返回类型必须与接口定义完全匹配?

接口实现上成员的返回类型必须与接口定义完全匹配?
EN

Stack Overflow用户
提问于 2011-11-03 13:59:36
回答 6查看 4.7K关注 0票数 12

根据CSharp语言规范。

接口定义了一个可以由类和结构实现的契约。接口不提供它定义的成员的实现-它只是指定必须由实现接口的类或结构提供的成员。

所以我有一个:

代码语言:javascript
运行
复制
interface ITest
{
    IEnumerable<int> Integers { get; set; }
}

我的意思是。“我与属性有一个契约,作为可以枚举的整数集合”。

然后,我需要以下接口实现:

代码语言:javascript
运行
复制
class Test : ITest
{
    public List<int> Integers { get; set; }
}

我得到以下编译器错误:

'Test‘不实现接口成员'ITest.Integers’。'Test.Integers‘不能实现'ITest.Integers’,因为它没有匹配的返回类型‘System.Collection tions.Generic.IEnDigable’。

只要我可以说,我的Test类实现了ITest契约,因为int属性列表实际上是int的IEnumerable。

那么c#编译器是如何告诉我错误的呢?

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2011-11-03 14:06:16

您不能这样做,因为如果允许的话,您将面临一个很大的问题,这取决于实现。考虑:

代码语言:javascript
运行
复制
interface ITest
{
    IEnumerable<int> Integers { get; set; }
}

class Test : ITest
{
    // if this were allowed....
    public List<int> Integers { get; set; }
}

这将允许:

代码语言:javascript
运行
复制
ITest test = new Test();
test.Integers = new HashSet<int>();

这将使用于测试的合同无效,因为Test说它包含List<int>

现在,可以使用显式接口实现来满足这两个签名,这取决于它是从ITest引用还是从Test引用调用的:

代码语言:javascript
运行
复制
class Test : ITest
{
    // satisfies interface explicitly when called from ITest reference
    IEnumerable<int> ITest.Integers
    {
        get
        {
            return this.Integers; 
        }
        set
        {
            this.Integers = new List<int>(value);
        }
    }

    // allows you to go directly to List<int> when used from reference of type Test
    public List<int> Integers { get; set; }
}
票数 10
EN

Stack Overflow用户

发布于 2011-11-03 14:45:49

FYI,您想要的特性称为“虚拟方法返回类型协方差”,正如您已经发现的,C#不支持它。它是其他面向对象语言的一个特性,比如C++。

虽然我们经常收到对这个特性的请求,但是我们没有计划将它添加到语言中。这不是一个可怕的特点,如果我们有它,我会使用它。但是我们有很多不这样做的理由,包括它没有得到CLR的支持,它为可修改的组件添加了新的有趣的故障模式,Anders并不认为它是一个非常有趣的特性,而且我们有很多很多更高的优先级和有限的预算。

顺便说一句,尽管人们一直要求我们使用虚拟方法返回类型协方差,但从来没有人要求虚拟方法形式参数类型反方差,尽管从逻辑上讲,它们本质上是相同的特征。也就是说,我有一个使用长颈鹿的虚拟方法/接口方法M,我想用一个带有动物的方法M来覆盖/实现它。

票数 20
EN

Stack Overflow用户

发布于 2011-11-03 14:05:36

简单的事实是,如果一个接口显示:

代码语言:javascript
运行
复制
IInterface{
   Animal A { get; }
}

然后,该属性的实现必须与类型完全匹配,完全是。试图将其实现为

代码语言:javascript
运行
复制
MyClass : IInterface{
  Duck A { get; }
}

不起作用--即使DuckAnimal

相反,您可以这样做:

代码语言:javascript
运行
复制
MyClass : IInterface{
  Duck A { get; }
  Animal IInterface.A { get { return A; } }
}

即提供IInterface.A成员的显式实现,利用DuckAnimal之间的类型关系。

在您的例子中,这意味着实现getter (至少是ITest.Integers )

代码语言:javascript
运行
复制
IEnumerable<int> ITest.Integers { get { return Integers; } }

要实现setter,您需要对输入值进行乐观的转换或使用.ToList()。

注意,在这些显式实现中使用AIntegers不是递归的,因为显式接口实现隐藏在类型的公共视图中--只有当调用者通过它的IInterface/ITest接口实现与该类型对话时,它们才会启动。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7996127

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档