Search code examples
c#.netgenericscontravariancenested-generics

Contravariance troubles with nested interfaces


interface IModel
{ 
}

class ModelA : IModel
{
}

interface IService<T> where T: IModel
{
}

class ServiceA : IService<ModelA>
{
}

Given the definition of classes and interfaces above, The following works:

IModel model = new ModelA();

Indicating that ModelA can be cast to its interface IModel

The following also works:

IService<ModelA> service1 = new ServiceA();

Indicating that ServiceA can be cast to its interface IService<ModelA>

However, the following fails:

IService<IModel> service2 = new ServiceA();

The error message says that ServiceA cannot be implicitly to converted to IService<IModel>

Im surprised by this since:
ModelA can be cast to IModel, and
ServiceA can be cast to IService<IModel>
i was expecting the following to happen:
ServiceA -> IService<ModelA> -> IService<IModel>

But that doesnt seem to be possible.

Anyone have an explanation to why that is?


Solution

  • The only real option you have here is to apply the out modifier on the generic type of IService making it Covariant

    Covariance enables you to use a more derived type than that specified by the generic parameter

    interface IService<out T> where T : IModel
    {
    }
    

    out (generic modifier) (C# Reference)


    To be specific, as much as it seems like it IService<IModel> is not the same thing as ServiceA : IService<ModelA>

    out means (roughly speaking), it can only appears in output positions.

    Be warned though, this will seriously limit what you can do with T.

    If you need to use T in IService (and it's not just a return of method in IService) , then you may need to use object or rethink the problem.