You have to tell the compiler that your interface is covariant : IAnimalStrategy<out T>
namespace GenericsTest
{
class Program
{
static void Main(string[] args)
{
List<IAnimalStrategy<IAnimal>> strategies = new List<IAnimalStrategy<IAnimal>>();
strategies.Add(new BarkStrategy());
}
}
interface IAnimal { }
interface IAnimalStrategy<out T> where T : IAnimal { }
class Dog : IAnimal { }
class BarkStrategy : IAnimalStrategy<Dog> { }
}
Unfortunately, it is available only in C# 4.0 : How is Generic Covariance & Contra-variance Implemented in C# 4.0?
For understanding the problem, you can forget the list, this line doesn't compile :
IAnimalStrategy<IAnimal> s = new BarkStrategy();
The IAnimalStrategy<IAnimal>
interface can do things on IAnimal, maybe set a property of type IAnimal
interface IAnimalStrategy<T> where T : IAnimal
{
T Animal {get; set;}
}
Then you would be able to do something like
IAnimalStrategy<IAnimal> s = new BarkStrategy();
s.Animal = new Cat();
It will blow in your face. So C#3.5 doesn't allow you to do that.
C#4.0 will allow you to that, if you said that T is covariant with the out
keyword
interface IAnimalStrategy<out T> where T : IAnimal
{
T Animal {get; set;}
}
This will blow again,
Invalid variance: The type parameter 'T' must be invariantly valid on
IAnimalStrategy.Animal'. 'T' is covariant.
Covariance and Contravariance are difficults to understand, I suggest you read the awesome series on Eric Lippert's Blog : Covariance and Contravariance in C#