Simulating covariant return types in C#
12 Sep 2008This post was imported from blogspot.
For several years, Microsoft engineers have refused to add support for covariant return types, a trivially simple feature that should have been in the CLR from the beginning.Suppose you want to write a Clone() method that returns a copy of the current object. Naturally you want to write the following, but it is illegal:
class MyStuff : ICloneable { public MyStuff Clone() { ... } }
Since you are implementing an interface, you can use this workaround that uses explicit interface implementation:
class MyStuff : ICloneable { public MyStuff Clone() { ... } object ICloneable.Clone() { return Clone(); } }
The above workaround is okay for implementing an interface, but what if you are writing a class hierarchy, and you want a Clone() method that is virtual but has the appropriate return type?
class BaseNode : ICloneable { object ICloneable.Clone() { return Clone(); } public virtual BaseNode Clone() { ... } } class ComplexNode : BaseNode { override BaseNode BaseNode.Clone() { return Clone(); } // Error! public ComplexNode Clone() { ... } }
Oops, the workaround that you use for interfaces is illegal for class inheritance. There is still a solution, though:
class BaseNode : ICloneable { object ICloneable.Clone() { return Clone(); } public BaseNode Clone() { BaseNode c; Clone(out c); return c; } protected virtual void Clone(out BaseNode clone) { ... } } class ComplexNode : BaseNode { public new ComplexNode Clone() { ComplexNode c; Clone(out c); return c; } protected override void Clone(out BaseNode clone) { clone = Clone(); } protected virtual void Clone(out ComplexNode clone) { ... } }
That's right. You need six Clone() methods. The last method is virtual in case you want to make a class derived from ComplexNode, e.g. VeryComplexNode:
class VeryComplexNode : ComplexNode { public new VeryComplexNode Clone() { VeryComplexNode c; Clone(out c); return c; } protected override void Clone(out BaseNode clone) { clone = Clone(); } protected override void Clone(out ComplexNode clone) { clone = Clone(); } protected virtual void Clone(out VeryComplexNode clone) { ... } }
Without covariant return types, you have to to define an additional virtual function for each additional derived class.