Search code examples
c#covariance

Does C# support return type covariance?


I'm working with the .NET framework and I really want to be able to make a custom type of page that all of my website uses. The problem comes when I am trying to access the page from a control. I want to be able to return my specific type of page instead of the default page. Is there any way to do this?

public class MyPage : Page
{
    // My own logic
}

public class MyControl : Control
{
    public MyPage Page { get; set; }
}

Solution


  • UPDATE: This answer was written in 2011. After two decades of people proposing return type covariance for C# they have been implemented. See Covariant Returns in https://devblogs.microsoft.com/dotnet/c-9-0-on-the-record/.


    It sounds like what you want is return type covariance. C# does not support return type covariance.

    Return type covariance is where you override a base class method that returns a less-specific type with one that returns a more specific type:

    abstract class Enclosure
    {
        public abstract Animal Contents();
    }
    class Aquarium : Enclosure
    {
        public override Fish Contents() { ... }
    }
    

    This is safe because consumers of Contents via Enclosure expect an Animal, and Aquarium promises to not only fulfill that requirement, but moreover, to make a more strict promise: that the animal is always a fish.

    This kind of covariance is not supported in C#, and is unlikely to ever be supported. It is not supported by the CLR. (It is supported by C++, and by the C++/CLI implementation on the CLR; it does so by generating magical helper methods of the sort I suggest below.)

    (Some languages support formal parameter type contravariance as well -- that you can override a method that takes a Fish with a method that takes an Animal. Again, the contract is fulfilled; the base class requires that any Fish be handled, and the derived class promises to not only handle fish, but any animal. Similarly, C# and the CLR do not support formal parameter type contravariance.)

    The way you can work around this limitation is to do something like:

    abstract class Enclosure
    {
        protected abstract Animal GetContents();
        public Animal Contents() { return this.GetContents(); }
    }
    class Aquarium : Enclosure
    {
        protected override Animal GetContents() { return this.Contents(); }
        public new Fish Contents() { ... }
    }
    

    Now you get both the benefits of overriding a virtual method, and getting stronger typing when using something of compile-time type Aquarium.