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

Dan*_*ker 17 c# language-features overriding interface explicit-implementation

在尝试ICollection<T>.IsReadOnlyCollection<T>类中覆盖属性的显式接口实现时,我遇到了一些文档,指出显式接口成员实现无法被覆盖,因为它们不能具有修饰符,如virtualabstract.在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)

然后你会期望一个Bcast 的实例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

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

  • 类型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,您应该理想地使用new在声明这些成员时修改BC.

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

20.4.2接口映射

特定接口成员的实现I.M,其中IM 声明成员的接口,通过检查每个类或结构来确定S,从C每个连续的基类开始并重复C,直到找到匹配为止.

20.4.4接口重新实现

允许继承接口实现的类通过将其包含在基类列表中来 重新实现接口.接口的重新实现遵循与接口的初始实现完全相同的接口映射规则.因此,继承的接口映射对于为接口的重新实现而建立的接口映射没有任何影响.