接口继承多个接口:这是如何由C#编译器处理的?

时间:2013-11-14 10:09:06

标签: c# .net interface mono

最近我发现C#允许

  

An interface can inherit from one or more base interfaces

例如,Caliburn.Micro中的IScreenhttp://caliburnmicro.codeplex.com/SourceControl/latest#src/Caliburn.Micro/IScreen.cs中执行此操作

namespace Caliburn.Micro
{
    public interface IScreen : IHaveDisplayName, IActivate, IDeactivate, 
        IGuardClose, INotifyPropertyChangedEx
    {
    }
}

我明白为什么这很有用,因为它意味着实现IScreen的类也需要实现其他接口。

但我想知道C#如何处理编译器和运行时明智。

这个问题的一些背景/背景:

我来自一个接口定义方法表的背景,实现接口的类既有自己的方法表,也有指向它们实现的接口的方法表的指针。

我脑海中浮现的各种问题源于我过去与人们进行的各种多层继承讨论,其中我认为它们也适用于此案例:

  • 如果接口能够从多个基接口继承,那么该表中方法的顺序如何?
  • 如果这些接口具有共同的祖先会怎样:这些方法会在表中多次出现吗?
  • 如果这些接口具有不同的祖先,但类似的方法名称怎么办?

(我在这里使用了单词methods,暗示接口中定义的属性将具有get_或set_方法)。

非常感谢对此的任何见解,以及有关如何更好地表达此问题的提示。

2 个答案:

答案 0 :(得分:9)

首先,让我们明确地说“接口继承”与基于类的继承并不完全相同(并且使用“继承”这两个词可能会产生误导)。

这是因为接口无法自行实例化,因此编译器/运行时对不必跟踪如何对独立接口类型进行虚拟调用(例如,您不需要知道如何调用{{ 1}} - 你只需要知道如何在特定类型的对象上调用 )。这允许在编译时以不同的方式处理事物。

现在我实际上知道编译器如何实现“接口继承”,但这是它如何做到的:

  

让接口能够从多个基接口继承,   该表中方法的顺序如何?

“派生”接口没有必要拥有一个方法表,该表包含来自其所有祖先接口的方法,因为它实际上并没有实现它们中的任何一个。每个接口类型只有一个它自己定义的方法表就足够了。

  

如果这些接口具有共同的祖先会是什么:那些方法   在表中多次出现?

鉴于上一个问题的答案,没有。最后,具体类型只会实现IEnumerable.GetEnumerator一次,无论IFoo出现在已实现接口的“层次结构”中多少次。 IFoo中定义的方法只会出现在IFoo的簿记表中。

  

如果这些接口具有不同的祖先,但类似的方法会怎样   名字?

再次,没问题。您需要使用适当的语法告诉编译器“这里是如何实现IFooIFoo.Frob”,但由于IBar.FrobIFoo的方法将映射到单独的表中,没有技术问题。

当然,这留下了“运行时如何调度方法?”的问题。无人接听。但是想象一个可能的解决方案并不困难:每个具体类型IBar都有指向它实现的每个接口的一个方法表的指针。当进行虚拟方法调用时,运行时会查看具体类型,找到将要调用其方法的接口的表(接口的类型是静态已知的)并进行调用。

答案 1 :(得分:1)

我无法谈论官方CLR如何做到这一点......但是Rotor发行版在对象vtable中积极地将公共接口祖先叠加在另一个上面。它还在适当的情况下将额外的SLOT分配到具体对象vtable中,从而减少了从具体类型跳转到接口vtable然后再到实现的需要。方法偏移在JIT时间计算。如果无法执行此优化,则单个方法可以多次占用vtable。

所以答案是(关于Rotor),它确实是一个实现细节,任何重叠/优化等都完全取决于编译器在编译类型时最好的决定。