Marc is right; just to give you some more background on why this cannot work. Consider the following re-naming of your code:
interface IZoo<TCage, TAnimal>
where TCage : ICage<TAnimal>
where TAnimal : IAnimal
{
}
class Zoo<TCage, TAnimal> : IZoo<TCage, TAnimal>
where TCage : ICage<TAnimal>
where TAnimal : IAnimal
{
}
interface ICage<TAnimal> where TAnimal : IAnimal
{
}
interface IAnimal
{
}
class FishTank<TAnimal> : ICage<TAnimal> where TAnimal : IAnimal
{
}
class Fish : IAnimal
{
}
And now your question is, why is this not legal:
Zoo<FishTank<Fish>, Fish> aquarium = new Zoo<FishTank<Fish>, Fish>();
IZoo<ICage<IAnimal>, IAnimal> zoo = aquarium;
?
Because suppose now there is a method on IZoo:
interface IZoo<TCage, TAnimal>
where TCage : ICage<TAnimal>
where TAnimal : IAnimal
{
void PutAnimalInCage(TCage cage, TAnimal animal);
}
And you then say:
zoo.PutAnimalInCage(giraffePaddock, giraffe);
And you just put a giraffe paddock into an aquarium! We cannot maintain type safety in a world where the conversion you want is legal and IZoo can have any method you choose on it.
Now, this is only dangerous because IZoo has such a method. If it doesn't have such a method then you are right, that could be perfectly safe. In C# 4.0 we added a feature to the language so that you can ask the compiler "check whether this interface can be made safely variant", by annotating the type parameters you want to be covariant with "out", and the ones you want to be contravariant with "in". If you do that then the compiler will check for you whether the variance you want can be made to be typesafe. If it cannot, then it will not allow the declaration of the type.
The way this question usually comes up on StackOverflow is people asking why is this illegal:
List<Giraffe> giraffes = new List<Giraffe>();
List<Mammal> mammals = giraffes; // illegal
Same reason. Because then nothing stops you from later
mammals.Add(new Tiger());
and you've just added a tiger to a list of giraffes. Same reasoning, just a much simpler case.