2010-11-17 38 views
3

绑定在瓦格纳的“Effective C#”,第23项,他解释说,接口早/晚在.net

接口方法不是 虚拟...他们是一个 具体实现的声明。

我发现这是一个难题,因为它意味着接口方法代表了早期绑定,但它们具有后期绑定的行为。它唤起了他们如何在封面下工作的好奇心。在C++中,这将变成对vtables的讨论。在C#中,我不知道它变成了什么。有人能说出来吗?

p.s.这个问题有a cousin,但是这个问题关注于接口。
p.p.s.请不要担心“你不需要知道它是如何工作的。”这又是一个好奇心。

回答

6

对,从语言的角度来看,它们并不是虚拟的。但他们实际上就CLR而言。此示例代码:

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

生成此IL为Dispose()方法:

.method public hidebysig newslot virtual final // <=== here 
     instance void Dispose() cil managed 
{ 
    // Unimportant 
} // end of method Example::Dispose 

注上的方法中的属性:虚拟最终。最后是确保你不能重写派生类中的方法。使接口方法的实现像语言中的非虚拟方法一样,但在运行时是虚拟方法。

然后这也回答你关于早/晚绑定的问题。现在很早,当班级被加载时,v表格插槽被填充。

+0

显然你的文章是我的答案。只有一个细节。你说一个接口代表早期绑定,但它肯定会展示后期绑定:'foreach(IMyInterface foo in Yahoo)foo.Run();'。在这种情况下,确定哪个'Run'方法要在加载类后发生,是吗?那不是迟到的约束? – 2010-11-17 21:34:55

+1

@Brent Arias - 这取决于你对“迟绑定”的定义。请参阅http://stackoverflow.com/questions/3842102/c-polymorphism/3842173#3842173 – 2010-11-17 21:51:10

+1

不,这是早期的限制。可以在不需要搜索可能的候选方法列表的情况下进行调用。迟绑定具有明确的含义,在C#中它涉及* dynamic *关键字或System.Reflection。关于接口方法调用的关键点是它们总是*间接调用(callvirt),而不是直接调用。尽管该语言表示他们不是虚拟的。 (我会避免提到C#甚至在非虚方法上使用callvirt来获得廉价的空检查)。 – 2010-11-17 21:51:23