Click here to monitor SSC

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 started off in the SQL Tools division, working on SQL Compare 7 and 8, moved onto Schema Compare for Oracle, and is now in the .NET division working on SmartAssembly.
<July 2010>
SuMoTuWeThFrSa
27282930123
45678910
11121314151617
18192021222324
25262728293031
1234567
How to Kill a Company in One Step or Save it in Three
 The majority of companies that suffer a major data loss subsequently go out of business. David Wesley... Read more...

Migrating from OCS 2007 R2 to Lync: Part 4
 Having migrated the rest of our users and legacy resources across, and start getting ready to... Read more...

Automated Script-generation with Powershell and SMO
 In the first of a series of articles on automating the process of building, modifying and copying SQL... Read more...

Seth Godin: Big in the IT Business
 Seth Godin has transformed our understanding of marketing in IT. He invented the concept of 'permission... Read more...

Using SQL Test Database Unit Testing with TeamCity Continuous Integration
 With database applications, the process of test and integration can be frustratingly slow because so... Read more...