co和contravariance的简单例子

Gra*_*ith 42 .net c# invariants covariance contravariance

有人能为我提供简单的C#例子,包括协方差,逆变,不变性和反不变性(如果存在这种情况).

到目前为止我见过的所有样品都只是投入一些物体System.Object.

Eri*_*ert 89

有人能为我提供简单的C#例子,包括协方差,逆变,不变性和反不变性(如果存在这种情况).

我不知道"反不变"是什么意思.其余的很容易.

这是协方差的一个例子:

void FeedTheAnimals(IEnumerable<Animal> animals) 
{ 
    foreach(Animal animal in animals)
        animal.Feed();
}
...
List<Giraffe> giraffes = ...;
FeedTheAnimals(giraffes);
Run Code Online (Sandbox Code Playgroud)

IEnumerable<T>接口是协变.事实上,长颈鹿可以转换为动物意味着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());
Run Code Online (Sandbox Code Playgroud)

Action<T>委托是逆变的.Frog可转换为Animal的事实意味着Action<Animal>可转换为Action<Frog>.注意这种关系是如何与协变方向相反的方向 ; 这就是为什么它是"对抗"的变种.由于可转换性,此代码成功; 它会在C#3中失败.

这应该是有道理的.动作可以采取任何动物; 我们需要一个可以接受任何青蛙的动作,并且可以采取任何动物的动作当然也可以采取任何青蛙.

不变性的一个例子:

void ReadAndWrite(IList<Mammal> mammals)
{
    Mammal mammal = mammals[0];
    mammals[0] = new Tiger();
}
Run Code Online (Sandbox Code Playgroud)

我们可以传递IList<Giraffe>给这件事吗?不,因为有人打算把老虎写进去,老虎不能列入长颈鹿名单.我们可以IList<Animal>传入这个东西吗?不,因为我们将从中读取一个哺乳动物,动物列表中可能包含一个青蛙. IList<T>不变的.它只能用于它实际的用途.

有关此功能设计的其他一些想法,请参阅我的系列文章,了解我们如何设计和构建它.

http://blogs.msdn.com/b/ericlippert/archive/tags/covariance+and+contravariance/

  • @Dan:好点.C#支持"损坏"的数组协方差,即使它们可能在运行时导致崩溃,也允许一些协变转换. (3认同)
  • 当然,在你的最后一个例子中可能值得指出,你*可以*将一个`Giraffe []`强制转换为'Mammal []`并将其传入,这将导致运行时错误. (2认同)
  • @Dan:或者,实际上不可变的数组类型,保证在初始化后不可写,将是安全协变的.我很想拥有这样的东西.数组是*变量*的集合这一事实经常令人烦恼; 我需要*值*的集合. (2认同)