Subterranean IL: Explicit overrides

Normally, virtual method overrides in .NET are done implicitly; if a subclass has a virtual method with the same name and signature as a virtual method in a base class, then the method in the subclass overrides the method in the base class:

This is in contrast to C# and VB, where a ‘base’ virtual method has to be declared as virtual, and all overrides of that method in subclasses have to be declared as override. But, similarly to IL, exactly which method it overrides in a base type depends on the name and signature of the methods concerned.

Explicit interface implementations

So what happens with explicit interface implementations? Well, IL and the assembly metadata allow you to specify a MethodImpl, which forces a method in the class to override one with a different name (but the same signature) in a base class. C# uses this mechanism to implement explicit interface overrides; this C#:

is compiled to this IL:

There are several interesting things to note here:

  1. The .override directive specifies the explicit override. Here, it forces MyClass::MyApp.IInterface.MyMethod to override IInterface::MyMethod.
  2. The explicit override method is named MyApp.IInterface.MyMethod. There is no necessity for any explicit overrides to be named anything in particular, but using this name format guarantees there won’t be any name conflicts in the same class; neither with normal C# code, as that can’t create method names with dots in, nor with any other explicit implementations, as the name contains the C# fully qualified name of the overridden method.
  3. The explicit override method is marked virtual final. In order to take part in any virtual method lookup, a method has to be declared virtual, even if the lookup information is ‘forced’ by an .override directive.
  4. The explicit override method is private. Although implicit overrides have to have at least the same accessibility as the method they’re overriding (ie you can’t implicitly override a public method with an internal one), these rules don’t apply to explicit overrides. In this case, the explicit override can only be called within MyClass or through the IInterface interface.

Abusing explicit overrides

Although .override is used by the C# compiler for explicit interface implementation, it is not limited to that. In fact, the only specific rules governing the use of .override are:

  • The signatures of the methods have to match (as I explored in an earlier post, you can’t implement override variance using explicit overrides). Explicit overrides only allow you to change the name.
  • The overridden method has to be in the type hierarchy of the containing class.
  • Both overridden and overriding methods have to be virtual.
  • The overridden method can’t be final.

That’s it. In particular, notice how there aren’t any restrictions on whether the overridden method is on an interface or concrete base class:

or on the number of .override declarations on a particular method:

or that the overriding method has to be private:

or that the use of explicit and implicit overrides are exclusive of each other:

or any combination of these. The use of explicit overrides is limited only by the compiler writer’s ingenuity.

Alternate explicit override syntax

As well as specifying .override inside the method body, you can also specify it in the class itself:

This leads onto the question as to whether you can use this syntax to link two disparate arms of a type’s inheritance heirarchy. As an example using implicit implementations:

but does this work for explicit implementations?

well, ilasm compiles it successfully, but it fails verification, and the CLR fails to load the dll:

Although this can be represented in the assembly metadata, the CLR specification disallows explicit overrides using methods in a base class (section 10.3.2). The overriding method must be in the same type as the .override directive.

This is a shame; this seems like a rather arbitary limitation, given that implicit implementations using base class methods work without errors. It would be interesting to hear from the CLR team as to why this limitation exists in the specification.

In the meantime, you can create a stub method in the implementing class to call the correct method on a base class (which is a technique sometimes used by the C# compiler).