C#:通过显式指定接口来覆盖属性

时间:2010-09-14 00:11:08

标签: c# interface override language-features explicit-implementation

在尝试覆盖ICollection<T>.IsReadOnly类的Collection<T>属性的显式接口实现时,我遇到了一些文档,指出显式接口成员实现无法被覆盖,因为它们不能具有修饰符,例如{ {1}}或virtual。在MSDN上,他们甚至通过创建另一个由显式接口成员实现调用的抽象或虚拟成员来指定如何使显式接口成员实现可用于继承。到目前为止没问题。

但后来我想知道:为什么C#可以通过明确指定接口 来覆盖任何显式实现的接口成员? < / p>

例如,假设我有一个这样的简单界面,带有属性和方法:

abstract

一个显式实现接口的类public interface IMyInterface { bool AlwaysFalse { get; } bool IsTrue(bool value); } ,并且有一个方法A,它调用自己的接口成员实现。

Test()

正如您所看到的,四个成员中没有一个是虚拟的或抽象的,所以当我定义一个类public class A : IMyInterface { bool IMyInterface.AlwaysFalse { get { return false; } } bool IMyInterface.IsTrue(bool value) { return value; } public bool Test() { return ((IMyInterface)this).AlwaysFalse; } } 时,这样:

B

然后,您希望将public class B : A { public bool AlwaysFalse { get { return true; } } public bool IsTrue(bool value) { return !value; } } 投射到B的实例表现得像A。它确实:

A

现在来了。创建一个类A a = new A(); Console.WriteLine(((IMyInterface)a).AlwaysFalse); // False Console.WriteLine(((IMyInterface)a).IsTrue(false)); // False Console.WriteLine(a.Test()); // False A b = new B(); Console.WriteLine(((IMyInterface)b).AlwaysFalse); // False Console.WriteLine(((IMyInterface)b).IsTrue(false)); // False Console.WriteLine(b.Test()); // False ,它是C的精确副本,除了类声明中的一件事:

B

现在public class C : A, IMyInterface { /* ... same as B ... */ } 的实例在转换为C时,其行为与A不同,但与A类似:

C

即使A c = new C(); Console.WriteLine(((IMyInterface)c).AlwaysFalse); // True Console.WriteLine(((IMyInterface)c).IsTrue(false)); // True Console.WriteLine(c.Test()); // True 方法现在调用Test()中的重写方法!这是为什么?

1 个答案:

答案 0 :(得分:10)

nothing 与显式接口实现有关;它只是继承和接口映射的一般规则的结果:如果类型A提供IMyInterface的隐式而非显式的实现,您会看到完全相同的结果

  • 类型B继承自A类型。什么都没有被覆盖 B提供了自己的AlwaysFalseIsTrue成员,但他们实施IMyInterface; IMyInterface继承的成员提供A的实现:当B类型的实例转换为IMyInterface时,它的行为方式与实例完全相同类型为A,因为A正在为实现该接口的成员提供。
  • 类型C继承自A类型。再一次,什么都没有被覆盖 C提供了自己的AlwaysFalseIsTrue成员,但这次成员实施IMyInterface:当C类型的实例时转换为IMyInterface然后C的成员提供接口实现,而不是A的接口实现。

因为类型A明确地实现了IMyInterface,所以编译器不会警告BC的成员隐藏A的成员;实际上,由于显式接口实现,A的成员已经被隐藏。

如果您更改了类型A以隐式而不是显式地实现IMyInterface,那么编译器会警告BC的成员隐藏,而不是覆盖, A的成员,在BC中声明这些成员时,理想情况下应使用new修饰符。

以下是语言规范中的一些相关位。 (ECMA-334 spec中的第20.4.2和20.4.4节; Microsoft C#4 spec中的第13.4.4和13.4.6节。)

  

20.4.2界面映射

     

特定的实施   接口成员I.M,其中I是   成员M的界面   声明,由...决定   检查每个类或结构S,   从C开始并重复   每个连续的基类C,   直到找到匹配。

     

20.4.4界面重新实施

     

继承接口的类   允许实施   重新实现接口   将它包含在基类列表中。一个   重新实现一个接口   遵循完全相同的界面   映射规则作为初始   实现接口。从而,   继承的接口映射没有   对界面产生任何影响   建立的映射   重新实现界面。