C# methods in interfaces are declared without using the virtual
keyword, and overridden in the derived class without using the override
keyword.
Is there a reason for this? I assume that it is just a language convenience, and obviously the CLR knows how to handle this under the covers (methods are not virtual by default), but are there other technical reasons?
Here is the IL that a derived class generates:
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
Notice that the method is declared virtual
final
in the IL.
For the interface, the addition of the abstract
, or even the public
keywords would be redundant, so you omit them:
interface MyInterface {
void Method();
}
In the CIL, the method is marked virtual
and abstract
.
(Note that Java allows interface members to be declared public abstract
).
For the implementing class, there are some options:
Non-overridable: In C# the class doesn't declare the method as virtual
. That means that it cannot be overridden in a derived class (only hidden). In the CIL the method is still virtual (but sealed) because it must support polymorphism regarding the interface type.
class MyClass : MyInterface {
public void Method() {}
}
Overridable: Both in C# and in the CIL the method is virtual
. It participates in polymorphic dispatch and it can be overridden.
class MyClass : MyInterface {
public virtual void Method() {}
}
Explicit: This is a way for a class to implement an interface but not provide the interface methods in the public interface of the class itself. In the CIL the method will be private
(!) but it will still be callable from outside the class from a reference to the corresponding interface type. Explicit implementations are also non-overridable. This is possible because there's a CIL directive (.override
) that will link the private method to the corresponding interface method that it's implementing.
[C#]
class MyClass : MyInterface {
void MyInterface.Method() {}
}
[CIL]
.method private hidebysig newslot virtual final instance void MyInterface.Method() cil managed
{
.override MyInterface::Method
}
In VB.NET, you can even alias the interface method name in the implementing class.
[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
}
Now, consider this weird case:
interface MyInterface {
void Method();
}
class Base {
public void Method();
}
class Derived : Base, MyInterface { }
If Base
and Derived
are declared in the same assembly, the compiler will make Base::Method
virtual and sealed (in the CIL), even though Base
doesn't implement the interface.
If Base
and Derived
are in different assemblies, when compiling the Derived
assembly, the compiler won't change the other assembly, so it will introduce a member in Derived
that will be an explicit implementation for MyInterface::Method
that will just delegate the call to Base::Method
.
So you see, every interface method implementation must support polymorphic behavior, and thus must be marked virtual on the CIL, even if the compiler must go through hoops to do it.