Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/314.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 接口实现上成员的返回类型必须与接口定义完全匹配?_C# - Fatal编程技术网

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

C# 接口实现上成员的返回类型必须与接口定义完全匹配?,c#,C#,根据CSharp语言规范 接口定义了一个可由类和 结构。接口不提供成员的实现 它定义它只是指定必须由提供的成员 实现接口的类或结构 所以我有一个: interface ITest { IEnumerable<int> Integers { get; set; } } 接口测试 { IEnumerable整数{get;set;} } 我的意思是。“我有一个契约,其中一个属性是可以枚举的整数集合” 然后我需要以下接口实现: class Test : ITest { p

根据CSharp语言规范

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

所以我有一个:

interface ITest
{
    IEnumerable<int> Integers { get; set; }
}
接口测试
{
IEnumerable整数{get;set;}
}
我的意思是。“我有一个契约,其中一个属性是可以枚举的整数集合”

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

class Test : ITest
{
    public List<int> Integers { get; set; }
}
类测试:ITest
{
公共列表整数{get;set;}
}
我得到以下编译器错误:

“Test”未实现接口成员“ITest.Integers”。 “Test.Integers”无法实现“ITest.Integers”,因为它没有实现 具有匹配的返回类型 'System.Collections.Generic.IEnumerable'

只要我能说我的测试类实现了ITest契约,因为int属性列表实际上是int的IEnumerable


那么c#编译器告诉我错误的方式呢?

因为测试不是ITest。为什么?使用ITest,可以将数组设置为属性整数。但你不能通过考试。
使用.net 4.0,您可以执行类似的操作(协方差和反方差),但不完全是这样,它在每种语言中都是不正确的。

您可以执行以下操作:

 interface ITest
{
    IEnumerable<int> Integers { get; set; }
}

class Test : ITest
{
    public IEnumerable<int> Integers { get; set; }

    public Test()
    {
        Integers = new List<int>();
    }
}
接口测试
{
IEnumerable整数{get;set;}
}
类别测试:ITest
{
公共IEnumerable整数{get;set;}
公开考试()
{
整数=新列表();
}
}

简单的事实是,如果界面显示:

IInterface{
   Animal A { get; }
}
然后,该属性的实现必须与类型完全匹配。试图将其实现为

MyClass : IInterface{
  Duck A { get; }
}
不起作用-即使
鸭子
动物

相反,您可以这样做:

MyClass : IInterface{
  Duck A { get; }
  Animal IInterface.A { get { return A; } }
}
即,提供
I接口.A
成员的显式实现,利用
Duck
Animal
之间的类型关系

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

IEnumerable<int> ITest.Integers { get { return Integers; } }
IEnumerable ITest.Integers{get{返回整数;}
要实现setter,需要对输入值进行乐观的强制转换或使用.ToList()


请注意,在这些显式实现中使用
A
Integers
不是递归的,因为显式接口实现在类型的公共视图中是隐藏的-它们仅在调用方通过
IInterface
/接口实现与类型对话时生效。

需要规范中的13.4.4:

出于接口映射的目的,类成员
a
在以下情况下与接口成员
B
匹配:

A
B
是属性,A和B的名称和类型相同,并且A与
B
具有相同的访问器(
A
如果不是显式接口成员实现,则允许有其他访问器)


此外,您认为
List Integers{get;set;}
满足
IEnumerable Integers{get;set;}
的约定是错误的。即使在某种程度上放宽了规范,不要求返回类型相同,请注意,带有公共setter的
List
类型的属性与带有公共setter的
IEnumerable
类型的属性并不接近,因为您可以为后者分配
int[]
的实例,但是对于前者,您不能这样做。

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

interface ITest
{
    IEnumerable<int> Integers { get; set; }
}

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

仅供参考,您想要的特性称为“虚拟方法返回类型协方差”,正如您所发现的,C#不支持该特性。它是其他面向对象语言的一个特征,如C++ ++。 虽然我们经常收到对该功能的请求,但我们没有计划将其添加到该语言中。这不是一个可怕的特征;如果我们有它,我会用它。但我们有很多理由不这样做,包括CLR不支持它,它为可版本组件添加了新的有趣的故障模式,Anders认为这不是一个非常有趣的功能,我们有很多更高的优先级和有限的预算


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

签名不一样。如果要实现接口,则需要实现相同的接口(协变/逆变泛型类型参数除外)列出如果您只想要“获取”,理论上应该是可能的。请参阅下面Eric Lippert关于如何在c#中实现这一点的帖子。在某些情况下,也可以只生成两个方法,一个称为IntegerList,另一个称为integernumerable。。然后整数实现在内部调用另一个方法;虽然相似,但它们是不同种类的协方差。C#4支持泛型类型协方差,但不支持返回类型协方差。我解释了为什么在他的例子中,它不是协方差,也不是反方差,它是不正确的。(请埃里克永远不要教我协变和逆变,这些术语来自法国数学家,我们知道如何使用它们以及它们是什么。)
ITest test = new Test();
test.Integers = new HashSet<int>();
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; }
}