接口实现上成员的返回类型必须与下层定义完全匹配?
根据CSharp语言规范。
接口定义了可以通过类和结构实现的契约。 接口不提供它定义的成员的实现 – 它仅指定必须由实现接口的类或结构提供的成员。
所以我有这个:
interface ITest { IEnumerable Integers { get; set; } }
我的意思是。 “我与一个属性的合同是一个你可以枚举的整数集合”。
然后我想要以下接口实现:
class Test : ITest { public List Integers { get; set; } }
我得到以下编译器错误:
‘Test’没有实现接口成员’ITest.Integers’。 ‘Test.Integers’无法实现’ITest.Integers’,因为它没有匹配的返回类型’System.Collections.Generic.IEnumerable’。
只要我可以说我的Test类实现了ITest契约,因为int属性的List实际上是int的IEnumerable。
那么c#编译器告诉我错误的方式呢?
你不能这样做,因为你手上有一个重大问题,具体取决于实施情况,如果这是允许的话。 考虑:
interface ITest { IEnumerable Integers { get; set; } } class Test : ITest { // if this were allowed.... public List Integers { get; set; } }
这将允许:
ITest test = new Test(); test.Integers = new HashSet();
这会使Test的合同无效,因为Test说它包含List
。
现在,您可以使用显式接口实现来允许它满足这两个签名,具体取决于它是从ITest
引用还是Test
引用调用:
class Test : ITest { // satisfies interface explicitly when called from ITest reference IEnumerable ITest.Integers { get { return this.Integers; } set { this.Integers = new List (value); } } // allows you to go directly to List when used from reference of type Test public List Integers { get; set; } }
仅供参考,您想要的function称为“虚方法返回类型协方差”,正如您所发现的那样,C#不支持它。 它是其他面向对象语言的一个特性,比如C ++。
虽然我们经常收到此function的请求,但我们没有计划将其添加到该语言中。 这不是一个可怕的特征; 如果我们拥有它,我会使用它。 但是我们有很多理由不这样做,包括CLR不支持它,它为可版本化的组件添加了新的和有趣的故障模式,Anders认为它不是一个非常有趣的function,而且我们有很多很多更高的优先级和有限的预算。
顺便说一下,尽管人们一直要求我们使用虚方法返回类型协方差,但是没有人要求虚方法forms参数类型相反 ,即使逻辑上它们本质上是相同的特征。 也就是说,我有一个带有长颈鹿的虚拟方法/接口方法M,我想用一个带动物的方法M来覆盖/实现它。
简单的事实是,如果界面说:
IInterface{ Animal A { get; } }
然后,该属性的实现必须与该类型完全匹配 。 试图将其实现为
MyClass : IInterface{ Duck A { get; } }
不起作用 – 即使Duck
是Animal
相反,你可以这样做:
MyClass : IInterface{ Duck A { get; } Animal IInterface.A { get { return A; } } }
即提供IInterface.A
成员的显式实现,利用Duck
和Animal
之间的类型关系。
在你的情况下,这意味着至少实现吸气剂,ITest.Integers为
IEnumerable ITest.Integers { get { return Integers; } }
要实现setter,您需要乐观地转换或在输入值上使用.ToList()。
请注意,在这些显式实现中使用A
和Integers
不是递归的,因为显式接口实现在类型的公共视图中是隐藏的 – 只有当调用者通过它的IInterface
/ ITest
接口实现与该类型对话时它们才会启动。
您需要规范中的13.4.4:
出于接口映射的目的,类成员
A
匹配接口成员B
:•
A
和B
是属性,A
和B
的名称和类型 相同 ,并且A具有与B
相同的访问器(A
不是显式接口成员实现,则允许A
具有其他访问者)。
另外,您认为List
List
满足IEnumerable
的合约IEnumerable
IEnumerable
是假的。 即使规范以某种方式放宽以不要求返回类型相同,请注意具有公共setter的List
类型的属性与具有公共setter的IEnumerable
类型的属性不同。因为对于后者你可以分配一个int[]
的实例,但对于前者你不能。
你可以这样做:
interface ITest { IEnumerable Integers { get; set; } } class Test : ITest { public IEnumerable Integers { get; set; } public Test() { Integers = new List (); } }
因为Test不是ITest。 为什么? 使用ITest,您可以将数组设置为属性Integers。 但你不能用一个测试。 使用.net 4.0,你可以做那样的事情(协方差和反方差),但不完全是这样,它在每种语言中都是不正确的。