Simon Cooper

Implementing method override covariance on C# (Part 1)

Published Wednesday, July 14, 2010 10:23 PM

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:

class A {
public Object method() { return new Object(); }
}

class B extends A {
@Override
public String method() { return new String(); }
}

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):

A a = new A();
B b = new B();
A ab = new B();

Object ao = a.method(); // ao is an Object
String bo = b.method(); // bo is a String
Object abo = ab.method(); // abo is a String

This is most useful when dealing with factory classes:

class Foo1 {}
class Foo2 extends Foo1 {}

class Foo1Factory {
public Foo1 getFoo() { /* ... */ }
}

class Foo2Factory extends Foo1Factory {
@Override
public Foo2 getFoo() { /* ... */ }
}

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:

error CS0508: 'B.Method()':
return type must be 'object' to match overridden member 'A.Method()'

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:

A ab = new B();
string abo = (string)ab.Method();

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.

Comments

No Comments
You need to sign in to comment on this blog

About Simon Cooper

Simon joined Red Gate as a software developer in 2007. He has spent most of his time on SQL Compare 7 and 8, where he concentrated on the SQL Compare engine. Other projects have included the new Check for Updates and work on the internal shared libraries. He is currently working on Schema Compare for Oracle, as Red Gate's first foray into the Oracle market.



















<July 2010>
SuMoTuWeThFrSa
27282930123
45678910
11121314151617
18192021222324
25262728293031
1234567
Minesweeper in T-SQL
 Whatever happened to the idea that programming in TSQL can be fun? A Simple-Talk reader contributes an... Read more...

SQL Source Control: The Development Story, Part II
 When creating SQL Source Control, the team had to make decisions as to which source control systems the... Read more...

Raw Materials: Healthy Caution or Something Else?
 Derek slips a cog. Read more...

The DIS-Information Principle, Part II
 Database design simply involves populating a schema with tables that model sets of entities and... Read more...

OCS Disaster Recovery, Part 2
 There are several possible disasters which might happen to your Office Communications Server... Read more...