我有一些通用的接口和类来实现这些接口,如下所示:
interface A<M, N>
where M : X<N>
where N : Y
{
}
class B<M, N> : A<M, N>
where M : X<N>
where N : Y
{
}
interface X<M> where M : Y
{
}
interface Y
{
}
class X1<M> : X<M> where M : Y
{
}
class Y1 : Y
{
}
我知道这似乎是一种非常混乱的做事方式,但我在申请时需要它。我的问题是我怎么能不这样做:
A<X<Y>, Y> variable = new B<X1<Y1>, Y1>();
答案 0 :(得分:8)
方差需要明确(并且需要C#4.0);例如,这使它编译为协变(注意接口中的out
修饰符):
interface A<out M, out N>
where M : X<N>
where N : Y
{
}
interface X<out M> where M : Y
{
}
但请注意,这也限制了您的界面......协方差!例如,您不能使用Add(M)
方法 - 因为它需要是可变的(aka in
)。
答案 1 :(得分:8)
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
{
}
现在你的问题是,为什么这不合法:
Zoo<FishTank<Fish>, Fish> aquarium = new Zoo<FishTank<Fish>, Fish>();
IZoo<ICage<IAnimal>, IAnimal> zoo = aquarium;
因为现在假设IZoo上有一个方法:
interface IZoo<TCage, TAnimal>
where TCage : ICage<TAnimal>
where TAnimal : IAnimal
{
void PutAnimalInCage(TCage cage, TAnimal animal);
}
然后你说:
zoo.PutAnimalInCage(giraffePaddock, giraffe);
你只需将长颈鹿围场放入水族馆!在您想要的转换合法且IZoo可以选择任何方法的世界中,我们无法保持类型安全。
现在,这只是危险的,因为IZoo有这样的方法。如果它没有这样的方法那么你是对的,这可能是非常安全的。在C#4.0中,我们为该语言添加了一个功能,以便您可以通过注释要与“out”协变的类型参数以及您想要的类型参数来询问编译器“检查此接口是否可以安全变换”。与“在”逆时针。如果您这样做,那么编译器将检查您是否可以使您想要的方差是类型安全的。如果不能,则不允许声明类型。
这个问题通常出现在StackOverflow上的方式是人们问为什么这是非法的:
List<Giraffe> giraffes = new List<Giraffe>();
List<Mammal> mammals = giraffes; // illegal
同样的道理。因为从那以后没有什么能阻止你
mammals.Add(new Tiger());
你刚刚在长颈鹿名单上添加了一只老虎。同样的推理,只是一个更简单的案例。