最近我发现C#允许
接口可以从一个或多个基接口继承。
例如, IScreen
在Caliburn.Micro这样做 http://caliburnmicro.codeplex.com/SourceControl/latest#src/Caliburn.Micro/IScreen.cs
namespace Caliburn.Micro
{
public interface IScreen : IHaveDisplayName, IActivate, IDeactivate,
IGuardClose, INotifyPropertyChangedEx
{
}
}
我明白为什么这很有用,因为它意味着一个类实现 IScreen
还需要实现其他接口。
但我想知道C#如何处理编译器和运行时明智。
这个问题的一些背景/背景:
我来自interface定义方法表的背景,实现接口的类既有自己的方法表,也有指向它们实现的接口的方法表的指针。
我脑子里浮现的子问题源于我过去与人们进行的各种多类继承讨论,我认为它们也适用于这种情况:
- 让接口能够从多个基接口继承,该表中的方法顺序如何?
- 如果这些接口具有共同的祖先会怎样:这些方法会在表中多次出现吗?
- 如果这些接口具有不同的祖先,但类似的方法名称怎么办?
(我在这里使用了单词methods,暗示接口中定义的属性将具有get_或set_方法)。
非常感谢对此的任何见解,以及如何更好地表达这个问题的提示。
首先,让我们明确地说“接口继承”与基于类的继承并不完全相同(并且使用“继承”这两个词可能会产生误导)。
那是因为接口无法自己实例化,因此编译器/运行时对不必跟踪如何为独立接口类型进行虚拟调用(例如,您不需要知道如何调用 IEnumerable.GetEnumerator
- 你只需要知道如何调用它 在特定类型的对象上)。这允许在编译时以不同方式处理事物。
现在我实际上并没有 知道 编译器如何实现“接口继承”,但这是如何做到的:
让接口能够从多个基接口继承,
该表中方法的顺序如何?
“派生”接口没有必要拥有一个方法表,该表包含来自其所有祖先接口的方法,因为它实际上并不实现它们中的任何一个。每个接口类型只有一个自己定义的方法表就足够了。
如果这些接口具有共同的祖先会是什么:那些方法
在表中多次出现?
鉴于上一个问题的答案,没有。最后,具体类型只会实现 IFoo
只需一次,无论多少次 IFoo
出现在已实现接口的“层次结构”中。方法定义于 IFoo
只会出现在 IFoo
的簿记表。
如果这些接口具有不同的祖先,但类似的方法会怎样
名字呢?
再说一遍,没问题。您需要适当的语法来告诉编译器“这里是如何实现的 IFoo.Frob
而且这里 IBar.Frob
“,但是因为方法 IFoo
和 IBar
将在单独的表中映射,没有技术问题。
当然,这留下了“运行时如何调度方法?”的问题。无人接听。但想象一个可能的解决方案并不难:每种具体类型 C
指向每个实现的接口的方法表。当进行虚拟方法调用时,运行时会查看具体类型,找到要调用其方法的接口的表(接口的类型是静态已知的)并进行调用。
我无法谈论官方CLR如何做到这一点......但是Rotor发行版在对象vtable中积极地将公共接口祖先叠加在一起。它还在适当的情况下将额外的SLOT分配到具体对象vtable中,从而减少了从具体类型跳转到接口vtable然后再到实现的需要。方法偏移在JIT时间计算。如果无法执行此优化,则单个方法可以多次占用vtable。
所以答案是(关于Rotor无论如何),它确实是一个实现细节,任何重叠/优化等都完全取决于编译器在编译类型时最好的决定。