Marc tiene razón; solo para darle más información sobre por qué esto no puede funcionar. Considere el siguiente cambio de nombre de su código:
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
{
}
Y ahora la pregunta es, ¿por qué no es esto legal:
Zoo<FishTank<Fish>, Fish> aquarium = new Zoo<FishTank<Fish>, Fish>();
IZoo<ICage<IAnimal>, IAnimal> zoo = aquarium;
?
Porque supongamos ahora hay un método en iZoo:
interface IZoo<TCage, TAnimal>
where TCage : ICage<TAnimal>
where TAnimal : IAnimal
{
void PutAnimalInCage(TCage cage, TAnimal animal);
}
Y luego dicen:
zoo.PutAnimalInCage(giraffePaddock, giraffe);
Y sólo hay que poner un prado jirafa en un acuario! No podemos mantener la seguridad de tipo en un mundo donde la conversión que desea es legal e IZoo puede tener cualquier método que elija.
Ahora, esto solo es peligroso porque IZoo tiene dicho método. Si no tiene dicho método, entonces tiene razón, eso podría ser perfectamente seguro. En C# 4.0 agregamos una característica al lenguaje para que pueda preguntar al compilador "verificar si esta interfaz se puede hacer de forma segura variante", al anotar los parámetros de tipo que desea que sean covariantes con "fuera", y los que desea ser contravariante con "en". Si lo hace, el compilador comprobará si la varianza que desea puede ser segura para el tipo. Si no puede, no permitirá la declaración del tipo.
La forma en que esta cuestión habitualmente aparece en StackOverflow es la gente que pregunta por qué es esto ilegal:
List<Giraffe> giraffes = new List<Giraffe>();
List<Mammal> mammals = giraffes; // illegal
misma razón. Porque entonces nada te detiene más tarde
mammals.Add(new Tiger());
y acabas de agregar un tigre a una lista de jirafas. Mismo razonamiento, solo un caso mucho más simple.
hey, Cuando intento hacer eso, dice que es la característica del lenguaje C# 4.0 y me sale un error, ¿qué debo hacer? – Twinhelix
@Twinhelix: ¿qué versión de Visual Studio está utilizando y a qué plataforma está apuntando? Funciona para mí en VS2010 targetting .NET 2.0. Antes de C# 4.0 ... la varianza no existía para casos muy limitados. –
Requiere C# 4.0. –