Though Olivier's answer gets the idea across about why this usually goes wrong, there is a way to make this work in your program.
The feature you want is called generic interface covariance. Covariance is the property that if a Cat
is an Animal
, then an IFoo<Cat>
is an IFoo<Animal>
.
Covariance in C# only works in the following situations:
- The "outer" type is an interface, delegate or array. No classes or structs.
- If an interface or delegate, the type must be marked at compile time as supporting covariance. Arrays get (unsafe!) covariance for free.
- The "inner" types -- the types that are varying -- are both reference types. You can't say that an
IFoo<int>
is an IFoo<object>
even though an int
is an object
, because they are not both reference types.
To mark an interface as covariant, you put out
before the declaration of the type parameter which you wish to allow to vary:
interface IImplementation<out TModel> where TModel : IModel { }
If you do that, your program will start to work.
HOWEVER, out
is a reminder to you that covariance is only safe if T
is used in output positions. This is legal:
interface I<out T> {
T M();
}
This is not:
interface I<out T> {
void M(T t);
}
In the first, T is only passed out of things. In the second, it is passed in.
In the first scenario, we cannot use covariance to introduce a type hole. We have an I<Cat>
and we cast it to I<Animal>
, and now M
returns an Animal
, but that's OK, because we already know that it will return a Cat
, and a Cat
is an Animal
.
But in the second scenario, we have the opposite situation. If we allowed an I<Cat>
to be converted to I<Animal>
then we have an M
that can take a Turtle
, but the real implementation can only handle Cat
s. That's why C# will make this illegal.
So go forth and use covariance, but remember that you have to certify to the compiler that you want it, and that it is safe under all circumstances. If you don't want it, or it is not safe, then you don't get to have covariance, and you'll have to find a different solution to your problem.