views:

316

answers:

6

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.

+1  A: 

They aren't virtual (in terms of how we think of them, if not in terms of underlying implementation as (sealed virtual) - good to read the other answers here and learn something myself :-)

They don't override anything - there is no implementation in the interface.

All the interface does is supply a "contract" that the class has to adhere to - a pattern, if you like, so that callers know how to call the object even if they have never seen that particular class before.

It is up to the class to then implement the interface method as it will, within the confines of the contract - virtual or "non-virtual" (sealed virtual as it turns out).

Jason Williams
@Jason everyone in this thread knows what interfaces are for. The question is extremely specific - the IL generated *is* virtual for the interface method and not virtual for a non-interface method.
Rex M
Yeah, it's really easy to criticize an answer after the question has been edited, isn't it?
Jason Williams
@Jason yeah, it is
Rex M
+14  A: 

Quoting Jeffrey Ritcher from CLR via CSharp 3rd Edition here

"The CLR requires that interface methods be marked as virtual. If you do not explicitly mark the method as virtual in your source code, the compiler marks the method as virtual and sealed; this prevents a derived class from overriding the interface method. If you explicitly mark the method as virtual, the compiler marks the method as virtual (and leaves it unsealed); this allows a derived class to override the interface method. If an interface method is sealed, a derived class cannot override the method. However, a derived class can re-inherit the same interface and can provide its own implementation for the interface’s methods."

Positive Zero
The quote doesn't say _why_ an interface method implementation is required to be marked virtual. It is because it's polymorphic with regards to the interface type, so it _needs_ a slot on the _virtual_ table to allow virtual method dispatching.
Jordão
+1  A: 

In most other compiled code environments, interfaces are implemented as vtables - a list of pointers to the method bodies. Typically a class that implements multiple interfaces will have somewhere in its internal compiler generated metadata a list of interface vtables, one vtable per interface (so that the method order is preserved). This is how COM interfaces are typically implemented as well.

In .NET, though, interfaces are not implemented as distinct vtables for each class. Interface methods are indexed through a global interface method table that all interfaces are a part of. Therefore, it is not necessary to declare a method virtual in order for that method to implement an interface method - the global interface method table can just point to the code address of the class's method directly.

Declaring a method virtual in order to implement an interface is not required in other languages either, even in non-CLR platforms. The Delphi language on Win32 is one example.

dthorpe
A: 

Yes, because a class implements an interface. In the case of an interface with one method, a class can choose to implement the method as a virtual, or to disallow overriding. Subclasses can then choose to override it or not. If this was defined at the interface level, it would significantly impact your codes flexibility. All an interface does is prove to the compiler that a property can be accessed or a call to a method can be made, it does not tell the compiler anything else about the implementer. For example structs can implement an interface, but can not be inherited from, so if you marked an interface method as virtual, you would exclude structs from implementing it.

Real John Connor
+1  A: 

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() {}
}

Implicit: 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. Implicits 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 : 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 implicit 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.

Jordão
+1  A: 

Yes, interface implementation methods are virtual as far as the runtime is concerned. It is an implementation detail, it makes interfaces work. Virtual methods get slots in the class' v-table, each slot has a pointer to one of the virtual methods. Casting an object to an interface type generates a pointer to the section of the table that implements the interface methods. The client code that uses the interface reference now sees the first interface method pointer at offset 0 from the interface pointer, etcetera.

What I under-appreciated in my original answer is the significance of the final attribute. It prevents a derived class from overriding the virtual method. A derived class must re-implement the interface, the implementation methods shadow the base class methods. Which is enough to implement the C# language contract that says that the implementation method is not virtual.

If you declare the Dispose() method in the Example class as virtual, you'll see the final attribute getting removed. Now allowing a derived class to override it.

Hans Passant