【问题标题】:interface inheriting multiple interfaces: how is this handled by a C# compiler?接口继承多个接口:C# 编译器如何处理?
【发布时间】:2013-11-14 10:09:06
【问题描述】:

最近我发现 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_方法)。

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

【问题讨论】:

  • 您的问题是关于在运行时在 CLR 中是如何表示的?或者编译器是如何执行的?
  • 你所有的项目符号只适用于一个具体的类,一个接口不继承任何实现,没有表也没有方法。接口方法到实现它的具体方法的映射是在运行时动态完成的,并且在调用该方法之前不会发生。下面的管道非常坚固,是 CLR 中使用汇编代码的少数几个地方之一。
  • @HansPassant:这些对你提供的深层内部结构的短暂一瞥令人抓狂! :-) 您能否提供相关 CLR 资源的链接?你从哪里得到这些信息?如果是原创研究,你会在任何地方发布结果吗?谢谢!
  • @HansPassant +1;谢谢你。我最初来自本机端的一部分,其中接口确实具有方法表以便具有 COM 兼容性。

标签: c# .net interface mono


【解决方案1】:

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

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

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

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

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

如果这些接口有共同的祖先会怎样:这些方法会怎样? 在表格中出现多次?

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

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

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

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

【讨论】:

  • 谢谢。我来自原生世界的一个地方,接口必须能够映射到 COM 接口,因此它们有表(并且不能从多个基本接口继承)。您的回答很有启发性,但我仍然想知道 CLR 如何每个接口有多个 vtable。我遇到了msdn.microsoft.com/en-us/magazine/cc163791.aspx#S12,这是.NET 1.1 的状态,monoruntime.wordpress.com/2009/04/22/… 是单声道,两者似乎都不支持继承多个基本类型的接口。
【解决方案2】:

我无法谈论官方 CLR 是如何做到这一点的。但是转子分布在对象 vtable 中积极地将公共接口祖先重叠在一起。它还在适当的地方将额外的 SLOT 分配到具体对象 vtable 中,从而减少从具体类型跳转到接口 vtable 再到实现的需要。方法偏移量是在 JIT 时间计算的。如果无法进行这种优化,那么单个方法可以多次占用 vtable。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-11
    • 2011-03-24
    • 1970-01-01
    • 2023-03-14
    • 2018-04-30
    相关资源
    最近更新 更多