The reason you cannot do this is because a list is writable. Suppose it were legal, and see what goes wrong:
List<Cat> cats = new List<Cat>();
List<Animal> animals = cats; // Trouble brewing...
animals.Add(new Dog()); // hey, we just added a dog to a list of cats...
cats[0].Speak(); // Woof!
Well dog my cats, that is badness.
The feature you want is called “generic covariance” and it is supported in C# 4 for interfaces that are known to be safe. IEnumerable<T>
does not have any way to write to the sequence, so it is safe.
class Animal
{
public virtual void Play(IEnumerable<Animal> animals) { }
}
class Cat : Animal
{
public override void Play(IEnumerable<Animal> animals) { }
}
class Program
{
static void Main()
{
Cat cat = new Cat();
cat.Play(new List<Cat>());
}
}
That will work in C# 4 because List<Cat>
is convertible to IEnumerable<Cat>
, which is convertible to IEnumerable<Animal>
. There is no way that Play can use IEnumerable<Animal>
to add a dog to something that is actually a list of cats.