17

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

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

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

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; }
}

然后你会期望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

现在来了。创建一个类,它是类声明中除了一件事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()方法现在也调用了C! 为什么是这样?

4

1 回答 1

11

这与显式接口实现无关;这只是继承和接口映射的一般规则的结果:如果 type提供AIMyInterface.

  • TypeB继承自 type A。没有任何东西被覆盖。
    B提供自己的AlwaysFalseIsTrue成员,但他们实施IMyInterface;的实现IMyInterface由继承自的成员提供A:当类型实例B被强制转换IMyInterface为时,它的行为方式与类型实例完全相同,A因为A它提供了实现接口的成员。
  • TypeC继承自 type A。同样,没有任何内容被覆盖。
    C提供它自己的AlwaysFalseIsTrue成员,但这次这些成员确实实现IMyInterface了:当类型的实例C被强制转换为时,IMyInterface的成员C提供接口实现而不是A.

因为 type显式A实现IMyInterface,编译器不会警告B和的成员C正在隐藏 ; 的成员A。实际上,A由于显式接口实现,这些成员已经被隐藏了。

如果您将类型更改为隐式A实现IMyInterface而不是显式实现,则编译器会警告Band的成员C正在隐藏而不是覆盖 and 的成员A,您最好new在声明这些成员时使用修饰符Band 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开始并重复,直到找到匹配项。CC

20.4.4 接口重新实现

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

于 2010-09-14T06:38:59.970 回答