Search code examples
c#covariancecontravariance

Covariance and Contravariance conversion fails


I know I'm missing something, but shouldn't this work!?

public interface IFoo<out TA, in TB>
    where TA : class
    where TB : class
{
}
public class Foo<T> : IFoo<T, T> where T : class { }
public class Whatever { }

...

Foo<Whatever> _Foo = new Foo<Whatever>(); // (changed "Foo" to "_Foo to be more clear)
var f = (IFoo<object, object>)_Foo; // CAST ERROR

FYI: The original project is .NET 4.0 using VS 2013.

Edit: It appears that an 'in' type for the 'TB' parameter (contravariance) must be either the SAME type, or a DERIVED type. Since 'object' is a supertype (as in, 'object' does not derive from type 'Whatever'), the conversion fails. (thanks to Aasmund Eldhuset)

This does work:

public class WhateverB : Whatever { }
var f = (IFoo<object, WhateverB>)Foo; // YAY ;)

Solution

  • A Foo<string> is not an IFoo<object, object>, because the generic type parameter TB doesn't match - for an in generic type parameter, the actual type must be equal to or be a superclass of the generic type parameter, but string is not a superclass of object.

    The reason the cast is accepted by the compiler is that a cast to an interface type is almost always legal (except in the corner case that PetSerAl mentions), because it could be that some subclass of the type you're casting from implements the interface.