Implementing method override covariance on C# (Part 1)

It has been said by many people that C# is ‘Java done right’ – it has many features that Java has, but implemented in a more sensible fashion (for example, generics) or concepts that wrap common coding patterns (properties and events). However, there is one feature not included in C# that I do miss from my time in Java – method override covariance (note that this is separate to generic co/contra-variance, which was added in C# 4; there’s an FAQ about that, and an article on wikipedia about covariance in general). As part of my project for the second Down Tools Week, I decided to see if anything could be done to add this small but useful feature to C#.

When a class overrides a method from its parent, Java allows you to change the overriding method return type to a subtype of the overridden method return type. For example:

This is entirely type safe, as an instance of a subtype can always be used wherever an instance of the parent type is required.

In the code above, when you call method on a reference of type A, you get a reference to an Object back. When called on a reference of type B, you get a String. Furthermore, B.Method overrides A.Method for virtual method dispatch (as enforced by the @Override annotation):

This is most useful when dealing with factory classes:

When you’ve got code that takes an instance of Foo2Factory, getFoo will be typechecked by the compiler as returning a Foo2, rather than a Foo1 – you don’t have to cast to Foo2 manually.

C#, however does not allow you to do this. Compiling the C# version of the first example above produces the following error:

The result of this is that whenever you need to use a subtype returned by an overridden method, you need to insert a cast to the subtype yourself:

Although a very small issue, I find this restriction very annoying when writing code dealing with lots of factory classes. It feels like something the compiler should be helping me with, but isn’t. In the next post, I’ll look at solving this problem in IL.


  • Rate
    [Total: 0    Average: 0/5]