接口中的C#方法在不使用virtual
关键字的情况下进行声明,并且在派生类中被覆盖,而在不使用override
关键字的情况下被重写。
这是否有原因?我认为这只是一种语言上的方便,显然CLR知道如何在后台进行处理(默认情况下方法不是虚拟的),但是还有其他技术原因吗?
这是派生类生成的IL:
class Example : IDisposable {
public void Dispose() { }
}
.method public hidebysig newslot virtual final
instance void Dispose() cil managed
{
// Code size 2 (0x2)
.maxstack 8
IL_0000: nop
IL_0001: ret
} // end of method Example::Dispose
注意,该方法在IL中已声明为virtual
final
。
对于接口,添加abstract
甚至是public
关键字都是多余的,因此您可以省略它们:
interface MyInterface {
void Method();
}
在CIL中,方法标记为virtual
和abstract
。
((请注意,Java允许将接口成员声明为public abstract
。
对于实现类,有一些选项:
Non-overridable:在C#中,类未将方法声明为virtual
。这意味着它不能在派生类中被覆盖(只能是隐藏的)。在CIL中,该方法仍然是虚拟的(但是密封的),因为它必须支持有关接口类型的多态性。
class MyClass : MyInterface {
public void Method() {}
}
Overridable:在C#和CIL中,方法均为virtual
。它参与多态调度,可以被覆盖。
class MyClass : MyInterface {
public virtual void Method() {}
}
Explicit:这是类实现接口的一种方法,但不提供类本身的公共接口中的接口方法。在CIL中,该方法将为private
(!),但仍可以从类外部通过对相应接口类型的引用进行调用。显式实现也是不可覆盖的。这是可能的,因为有一个CIL指令(.override
)将私有方法链接到它正在实现的相应接口方法。]
[C#]
class MyClass : MyInterface {
void MyInterface.Method() {}
}
[CIL]
.method private hidebysig newslot virtual final instance void MyInterface.Method() cil managed
{
.override MyInterface::Method
}
在VB.NET中,您甚至可以在实现类中为接口方法名称加上别名。
[VB.NET]
Public Class MyClass
Implements MyInterface
Public Sub AliasedMethod() Implements MyInterface.Method
End Sub
End Class
[CIL]
.method public newslot virtual final instance void AliasedMethod() cil managed
{
.override MyInterface::Method
}
现在,考虑这个奇怪的情况:
interface MyInterface {
void Method();
}
class Base {
public void Method();
}
class Derived : Base, MyInterface { }
如果Base
和Derived
在同一程序集中声明,则即使Base::Method
未实现该接口,编译器也会将Base
设为虚拟且密封(在CIL中)。
如果Base
和Derived
位于不同的程序集中,则在编译Derived
程序集时,编译器将不会更改其他程序集,因此它将在Derived
中引入一个成员,该成员将明确实现MyInterface::Method
会将呼叫仅委派给Base::Method
。
因此,您看到,每个
接口方法实现必须支持多态行为,因此即使编译器必须经过箍才能做到这一点,也必须在CIL上将其标记为虚拟。此处通过CSharp第三版从CLR引用Jeffrey Ritcher
是的,就运行时而言,接口实现方法是虚拟的。这是一个实现细节,它使接口正常工作。虚拟方法在类的v表中获取插槽,每个插槽都有一个指向虚拟方法之一的指针。将对象强制转换为接口类型会生成一个指向实现接口方法的表部分的指针。现在,使用接口引用的客户端代码将看到第一个接口方法指针,该指针与接口指针等距偏移量0。