Для интерфейса добавление ключевых слов 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, даже если компилятор должен пройти через обручи, чтобы сделать это.