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