对于界面,添加abstract,甚至public 关键字都是多余的,所以你可以省略它们:
interface MyInterface {
void Method();
}
在 CIL 中,方法标记为 virtual 和 abstract。
(请注意,Java 允许将接口成员声明为public abstract)。
对于实现类,有一些选项:
不可覆盖:在 C# 中,类不会将方法声明为 virtual。这意味着它不能在派生类中被覆盖(仅隐藏)。在 CIL 中,该方法仍然是虚拟的(但密封的),因为它必须支持关于接口类型的多态性。
class MyClass : MyInterface {
public void Method() {}
}
可重写:在 C# 和 CIL 中,方法都是 virtual。它参与多态调度,并且可以被覆盖。
class MyClass : MyInterface {
public virtual void Method() {}
}
显式:这是类实现接口但不在类本身的公共接口中提供接口方法的一种方式。在 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 虚拟和密封(在CIL 中),即使Base 没有实现接口。
如果Base和Derived在不同的程序集中,编译Derived程序集时,编译器不会改变另一个程序集,所以它会在Derived中引入一个成员,这将是一个显式实现对于MyInterface::Method,只会将调用委托给Base::Method。
所以你看,每个接口方法实现都必须支持多态行为,因此必须在 CIL 上标记为虚拟,即使编译器必须费力地完成它。