代码之家  ›  专栏  ›  技术社区  ›  Daniel A.A. Pelsmaeker

C:通过显式指定接口来重写属性

  •  16
  • Daniel A.A. Pelsmaeker  · 技术社区  · 14 年前

    尝试重写的显式接口实现时, ICollection<T>.IsReadOnly 属性来自 Collection<T> 类,我遇到一些文档,这些文档声明不能重写显式接口成员实现,因为它们不能有修饰符,例如 virtual 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; }
    }
    

    那么你会期待一个 强制转换为 表现得像 . 它做到了:

    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 哪一个是 除了类声明中的一件事:

    public class C : A, IMyInterface
    { /* ... same as B ... */ }
    

    现在是 C ,当强制转换为 ,行为不象 但就像 C :

    A c = new C();
    Console.WriteLine(((IMyInterface)c).AlwaysFalse);    // True
    Console.WriteLine(((IMyInterface)c).IsTrue(false));  // True
    Console.WriteLine(c.Test());                         // True
    

    即使是 测试() 方法现在调用重写的方法 C !这是为什么?

    1 回复  |  直到 14 年前
        1
  •  10
  •   LukeH    14 年前

    这个有 没有什么 处理显式接口实现;这只是继承和接口映射的一般规则的结果:您将看到 确切地 如果类型为 A 提供了一个隐式而非显式的 IMyInterface .

    • 类型 B 从类型继承 . 不会覆盖任何内容。
      提供自己的 AlwaysFalse IsTrue 但他们 不要 实施 界面 ;实施 界面 由继承自的成员提供 :当类型的实例 被强制转换为 界面 然后它的行为方式与类型的实例完全相同 因为 正在提供实现接口的成员。
    • 类型 C 从类型继承 . 同样,不会覆盖任何内容。
      C 提供自己的 总是如此 特雷西 但这次那些成员 实施 界面 :当类型的实例 C 被强制转换为 界面 然后是的成员 C 提供接口实现,而不是 .

    因为类型 工具 界面 显式地,编译器不会警告 C 正在隐藏的成员 ;实际上,这些成员 由于显式接口实现,已隐藏。

    如果你改变了类型 实施 界面 则编译器将隐式而非显式地警告 C 正在隐藏,而不是覆盖 你最好使用 new 在中声明这些成员时的修饰符 C .

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

    20.4.2接口映射

    特定的执行 接口成员 I.M ,在哪里 I 是 成员所在的接口 M 声明,由 检查每个类或结构 S , 从开始 C 重复 的每个连续基类 C , 直到找到匹配。

    20.4.4接口重新实现

    继承接口的类 允许实施 重新实施 接口由 包括在基类列表中。一 接口的重新实现 遵循完全相同的接口 将规则映射为初始值 接口的实现。因此, 继承的接口映射没有 对界面的任何影响 为建立映射 重新实现接口。

    推荐文章