Derived type cannot be implicitly converted to base interface

Tag: .net-3.5 , inheritance , interface , c#-3.0 Author: aileen85 Date: 2010-10-24
interface IModel {}

class MyModel : IModel {}

interface IRepo<T>
    where T: IModel { }

class Repo : IRepo<MyModel> { }

//EDIT: A smaller example
IRepo<IModel> repo = new Repo(); // Cannot implicitly convert.. An explicit convertion exists. Missing cast?

// Old example:
/*
The type 'Repo' cannot be used as type parameter 'C' in the generic type or method.
'Castle.MicroKernel.Registration.ComponentRegistration<S>.ImplementedBy<C>()'.
==> There is no implicit reference conversion from 'Repo' to 'IRepo<IModel>'.
*/
container.Register(
    Component.For<IRepo<IModel>>()
   .ImplementedBy<Repo>());

But Repo is derived from IRepo, and MyModel is derived from IModel. Why doesn't this work?

I tried adding an implicit operator on Repo, but it's not allowed to convert between interfaces..

Is this solved by the co/contra varience thing from c#4 (No, I don't have a clue what I'm talking about :) )?

Best Answer

Your intuition was right. This is a covariance issue. You see, IRepo<IModel> and IRepo<MyModel> are not the same.

To allow for covariant types, you can fix it with the out modifier in C# 4:

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

If you are not on C# 4 yet, you will need to tighten your usage:

IRepo<MyModel> repo = new Repo();

comments:

Thanks. Guess it's time to think about upgrading to c#4 then..

Other Answer1

You are correct. It does not work because of Co/Contravariance. It is supposed to work in C# 4 (I didn´t test it because I never needed such a thing :P).

A good explanation on how it works can be found here: http://blogs.msdn.com/b/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx

comments:

It doesn't work out of the box in C# 4. The IRepo interface needs to be modified with the covariance modifier: out.