在.Net中的接口早期/晚期绑定

10 浏览
0 Comments

在.Net中的接口早期/晚期绑定

在瓦格纳的《Effective C#》书中,第23条中解释到,接口方法不是虚拟的...它们是具体实现的声明。

这让我感到困惑,因为它意味着接口方法代表了早期绑定,但它们却具有晚期绑定的行为。这激发了我对它们在内部是如何工作的好奇心。在C++中,这将变成有关虚函数表的讨论。在C#中,我不知道会变成什么。有人能解释一下吗?

附注:这个问题有一个类似问题,但是这个问题关注的是接口。

附注:请不要担心"你不需要知道它是如何工作的"。再次强调,这只是出于好奇心。

0
0 Comments

在.Net中,接口的早期绑定和晚期绑定的出现是由于CLR在运行时对接口方法的处理方式。在编程语言的角度上看,接口方法并不是虚方法,但在CLR的角度上看,它们实际上是虚方法。通过以下示例代码可以看出:

class Example : IDisposable {
    public void Dispose() {}
}

Dispose()方法的IL代码如下:

.method public hidebysig newslot virtual final // <=== 这里

instance void Dispose() cil managed

{

// Unimportant

} // end of method Example::Dispose

注意方法上的属性:virtual和final。final属性确保在派生类中无法重写该方法。这使得接口方法的实现在语言层面上表现为非虚方法,在运行时却是虚方法。

这也回答了你关于早期绑定和晚期绑定的问题。在这种情况下,当类被加载时,v-table中的槽位就被填充了,因此属于早期绑定。

显然,你的问题已经得到了解答。只有一个细节需要说明。你说接口代表早期绑定,但它实际上表现出晚期绑定:foreach(IMyInterface foo in Yahoo) foo.Run();。在这种情况下,确定调用哪个Run方法必须在类加载之后进行,是吗?为什么这不是晚期绑定?

Arias - 这取决于你对"晚期绑定"的定义。请参考stackoverflow.com/questions/3842102/…

不,这是早期绑定。调用可以在不需要搜索可能的候选方法列表的情况下进行。晚期绑定在C#中有一个明确定义的含义,它涉及到dynamic关键字或System.Reflection。关于接口方法调用的关键点是它们始终是间接调用(callvirt),而不是直接调用。即使语言上说它们不是虚方法。(我将避免提到C#在非虚方法上也使用callvirt以实现廉价的空引用检查)。

0