有人可以给我提供简单的 C# 示例,例如协变、逆变、不变和反不变(如果存在的话)。
我不知道“反不变性”是什么意思。其余的都很简单。
这是一个协方差的例子:
void FeedTheAnimals(IEnumerable<Animal> animals)
{
foreach(Animal animal in animals)
animal.Feed();
}
...
List<Giraffe> giraffes = ...;
FeedTheAnimals(giraffes);
IEnumerable<T> 接口是协变的。 Giraffe 可转换为 Animal 的事实意味着 IEnumerable<Giraffe> 可转换为 IEnumerable<Animal>。由于List<Giraffe> 实现IEnumerable<Giraffe>,此代码在C# 4 中成功;它在 C# 3 中会失败,因为 IEnumerable<T> 上的协方差在 C# 3 中不起作用。
这应该是有道理的。一个长颈鹿序列可以被视为一个动物序列。
这是一个逆变的例子:
void DoSomethingToAFrog(Action<Frog> action, Frog frog)
{
action(frog);
}
...
Action<Animal> feed = animal=>{animal.Feed();}
DoSomethingToAFrog(feed, new Frog());
Action<T> 委托是逆变的。 Frog 可转换为 Animal 的事实意味着 Action<Animal> 可转换为 Action<Frog>。注意这种关系是如何与协变关系相反的;这就是为什么它是“对立”变体。由于可兑换,此代码成功;在 C# 3 中它会失败。
这应该是有道理的。该动作可以采取任何动物;我们需要一个可以带走任何 Frog 的动作,一个可以带走任何 Animal 的动作肯定也可以带走任何 Frog。
不变性的一个例子:
void ReadAndWrite(IList<Mammal> mammals)
{
Mammal mammal = mammals[0];
mammals[0] = new Tiger();
}
我们可以将IList<Giraffe> 传递给这个东西吗?不,因为有人要在其中写入老虎,而老虎不能出现在长颈鹿列表中。我们可以将IList<Animal> 传递给这个东西吗?不,因为我们要从中读取哺乳动物,而动物列表可能包含一只青蛙。 IList<T> 是不变的。只能按实际情况使用。
有关此功能设计的其他想法,请参阅我关于我们如何设计和构建它的系列文章。
http://blogs.msdn.com/b/ericlippert/archive/tags/covariance+and+contravariance/