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

继承多个接口的接口:C#编译器如何处理这个问题?,c#,.net,interface,mono,C#,.net,Interface,Mono,最近我发现C#允许 例如,Caliburn.Micro中的IScreen在 我明白了为什么这很有用,因为它意味着实现IScreen的类还需要实现其他接口 但我想知道C#如何处理编译器和运行时 这个问题的一点背景/背景: 我来自这样一个背景:接口定义了一个方法表,实现接口的类既有自己的方法表,也有指向它们实现的接口的方法表的指针 我脑海中萦绕的子问题源于我过去与人们进行的各种多类继承讨论,我认为这些讨论也适用于本案例: 如果一个接口能够从多个基本接口继承,那么该表中方法的顺序如何 如果这些接口

最近我发现C#允许

例如,Caliburn.Micro中的
IScreen

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

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

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

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

我脑海中萦绕的子问题源于我过去与人们进行的各种多类继承讨论,我认为这些讨论也适用于本案例:

  • 如果一个接口能够从多个基本接口继承,那么该表中方法的顺序如何
  • 如果这些接口有共同的祖先会怎样:这些方法会在表中出现多次吗
  • 如果这些接口有不同的祖先,但有相似的方法名呢
(我在这里使用单词methods,这意味着在接口中定义的属性将有一个get_u或set_u方法)


对此的任何见解以及如何更好地表达这个问题的技巧都是非常值得赞赏的。

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

这是因为接口本身无法实例化,因此编译器/运行时对不必跟踪如何对独立接口类型进行虚拟调用(例如,您不需要知道如何调用
IEnumerable.GetEnumerator
——您只需要知道如何对特定类型的对象调用它)。这允许在编译时以不同的方式处理事情

现在我不知道编译器是如何实现“接口继承”的,但下面是它如何实现的:

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

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

如果这些接口有共同的祖先呢:这些方法 是否在表中多次出现

对于前面的问题,答案是否定的。最终,一个具体类型只会实现一次
IFoo
,而不管
IFoo
在已实现接口的“层次结构”中出现多少次。在
IFoo
中定义的方法将仅出现在
IFoo
的簿记表中

如果这些接口有不同的祖先,但方法相似呢 名字

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


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

我无法说明官方CLR是如何进行调用的。。但是,转子分布在对象vtable中主动地将公共接口祖先重叠在彼此之上。它还可以在适当的情况下为具体对象vtable分配额外的插槽,从而减少从具体类型到接口vtable再到实现的需要。。方法偏移量在JIT时间计算。如果无法执行此优化,则单个方法可以多次占用vtable


所以答案是(无论如何,关于Rotor),它实际上是一个实现细节,任何覆盖/优化等都完全取决于编译器在编译类型时决定的最佳方式。

您的问题是如何在CLR中在运行时表示这一点?或者编译器是如何执行它的?你所有的项目符号都只适用于一个具体的类,一个接口不继承任何实现,没有表,也没有方法。接口方法到实现它的具体方法的映射是在运行时动态完成的,在调用该方法之前不会发生。下面的管道非常坚固,是CLR中少数几个使用汇编代码的地方之一。@HansPassant:这些对您提供的深层内部结构的短暂一瞥令人发狂!:-)你能提供相关CLR资源的链接吗?你从哪里得到这些信息?如果是原创研究,你会在任何地方发表研究结果吗?谢谢@汉斯帕桑+1;谢谢你。我最初来自本机端的一个部分,在那个里接口确实有一个方法表,以便具有COM兼容性。谢谢。我来自原生世界的一个地方,在那里接口必须能够映射到COM接口,因此它们有表(并且不能从多个基本接口继承)。您的回答很有启发性,但我仍然想知道CLR如何能在每个接口上有多个vtables。我遇到了一个是.NET1.1状态,另一个是mono,两者似乎都不支持继承多个基类型的接口。
namespace Caliburn.Micro
{
    public interface IScreen : IHaveDisplayName, IActivate, IDeactivate, 
        IGuardClose, INotifyPropertyChangedEx
    {
    }
}