Dan*_*ker 17 c# language-features overriding interface explicit-implementation
在尝试ICollection<T>.IsReadOnly
从Collection<T>
类中覆盖属性的显式接口实现时,我遇到了一些文档,指出显式接口成员实现无法被覆盖,因为它们不能具有修饰符,如virtual
或abstract
.在MSDN上,他们甚至通过创建另一个由显式接口成员实现调用的抽象或虚拟成员来指定如何使显式接口成员实现可用于继承.到目前为止没问题.
但后来我想:为什么有可能在C#重写任何刚刚通过指定接口的显式实现接口成员明确?
例如,假设我有一个这样的简单接口,具有属性和方法:
public interface IMyInterface
{
bool AlwaysFalse { get; }
bool IsTrue(bool value);
}
Run Code Online (Sandbox Code Playgroud)
还有一个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; }
}
Run Code Online (Sandbox Code Playgroud)
如您所见,四个成员中没有一个是虚拟的或抽象的,所以当我定义这样的类时B
:
public class B : A
{
public bool AlwaysFalse
{ get { return true; } }
public bool IsTrue(bool value)
{ return !value; }
}
Run Code Online (Sandbox Code Playgroud)
然后你会期望一个B
cast 的实例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
Run Code Online (Sandbox Code Playgroud)
现在来了.创建一个类C
,它是B
类声明中除一件事之外的精确副本:
public class C : A, IMyInterface
{ /* ... same as B ... */ }
Run Code Online (Sandbox Code Playgroud)
现在,一个实例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
Run Code Online (Sandbox Code Playgroud)
即使该Test()
方法现在调用重写方法C
!为什么是这样?
Luk*_*keH 11
这与显式接口实现无关 ; 它只是继承和接口映射的一般规则的结果:如果类型提供了隐式而非显式的实现,您会看到完全相同的结果.A
IMyInterface
B
继承自类型A
.什么都没有被覆盖.B
提供自己的AlwaysFalse
和IsTrue
成员,但他们没有实施IMyInterface
; 的实现IMyInterface
是由成员提供继承A
:当类型的实例B
强制转换IMyInterface
那么它在完全相同的方式表现为类型的实例A
,因为A
是提供实现接口的成员.C
继承自类型A
.再说一遍,什么都没有被覆盖.C
提供了自己AlwaysFalse
和IsTrue
成员,但此时这些成员做实现IMyInterface
:当类型的实例C
被强制转换IMyInterface
的,则成员C
提供的接口实现,而不是那些A
.因为类型A
实现了IMyInterface
显式,所以编译器不会警告成员B
和C
隐藏成员A
; 实际上,A
由于显式接口实现,这些成员已经被隐藏.
如果您更改输入A
实现IMyInterface
隐含而不是明确,则编译器会警告说,成员B
和C
被隐藏,不重写,成员A
,您应该理想地使用new
在声明这些成员时修改B
和C
.
以下是语言规范中的一些相关位.(ECMA-334规范中的第20.4.2和20.4.4节; Microsoft C#4规范中的第13.4.4和13.4.6节)
20.4.2接口映射
特定接口成员的实现
I.M
,其中I
是M
声明成员的接口,通过检查每个类或结构来确定S
,从C
每个连续的基类开始并重复C
,直到找到匹配为止.20.4.4接口重新实现
允许继承接口实现的类通过将其包含在基类列表中来 重新实现接口.接口的重新实现遵循与接口的初始实现完全相同的接口映射规则.因此,继承的接口映射对于为接口的重新实现而建立的接口映射没有任何影响.