C#中的协方差是什么? (或,协方差:例如)
协方差(粗略地)在使用它们的复杂类型中镜像“简单”类型的继承的能力.
例如.我们总是可以把猫的一个例子视为动物的一个例子.复杂类型< Cat>可以被视为ComplexType< Animal>如果ComplexType是协方差的. 我想知道:协方差的“类型”是什么,它们如何与C#相关(是否支持?) 例如,一种类型是返回类型协方差,由Java支持,但不是C#. 我希望有功能的编程人员也可以进来, 解决方法
这是我能想到的:
更新 阅读建设性意见和Eric Lippert指出(和写的)大量文章后,我改进了答案: 更新了阵列协方差的破坏 返回类型协方差: C#中不支持Java(> = 5) class B { B Clone(); } class D: B { D Clone(); } 界面协方差 BCL将通用的IEnumerable接口定义为协变量: IEnumerable<out T> {...} 因此,以下示例是有效的: class Animal {} class Cat : Animal {} IEnumerable<Cat> cats = ... IEnumerable<Animal> animals = cats; 请注意,IEnumerable的定义是“只读” – 您不能向其添加元素. public interface IEnumerable<out T> : ... //covariant - notice the 'out' keyword public interface IList<T> : ... //invariant 代表协方差方法组 class Animal {} class Cat : Animal {} class Prog { public delegate Animal AnimalHandler(); public static Animal GetAnimal(){...} public static Cat GetCat(){...} AnimalHandler animalHandler = GetAnimal; AnimalHandler catHandler = GetCat; //covariance } “纯”代表协方差 没有参数并返回某些东西的委托的BCL定义是协变的: public delegate TResult Func<out TResult>() 这允许以下内容: Func<Cat> getCat = () => new Cat(); Func<Animal> getAnimal = getCat; 数组协方差 – 支持C#,破碎的方式 string[] strArray = new[] {"aa","bb"}; object[] objArray = strArray; //covariance: so far,so good //objArray really is an "alias" for strArray (or a pointer,if you wish) //i can haz cat? object cat == new Cat(); //a real cat would object to being... objectified. //now assign it objArray[1] = cat //crash,boom,bang //throws ArrayTypeMismatchException 最后 – 令人惊讶和有点头脑弯曲 承担一个参数并且不返回任何事件的委托的BCL定义是相反的: public delegate void Action<in T>(T obj) 跟我一起让我们来定义一个马戏团的动物训练师 – 他可以被告知如何训练一只动物(通过给他一个与该动物合作的动作). delegate void Trainer<out T>(Action<T> trainingAction); 我们有训练师的定义,让我们得到一个教练,让他上班. Trainer<Cat> catTrainer = (catAction) => catAction(new Cat()); Trainer<Animal> animalTrainer = catTrainer; // covariant: Animal > Cat => Trainer<Animal> > Trainer<Cat> //define a default training method Action<Animal> trainAnimal = (animal) => { Console.WriteLine("Training " + animal.GetType().Name + " to ignore you... done!"); }; //work it! animalTrainer(trainAnimal); 输出证明这是有效的:
为了理解这个,一个笑话是有序的.
这与协方差有什么关系? 让我尝试一下餐巾纸展示. 动作< T>是逆转的,即它“翻转”类型的关系: A < B => Action<A> > Action<B> (1) 使用动作< A>更改上述A和B和Action< B>并得到: Action<A> < Action<B> => Action<Action<A>> > Action<Action<B>> or (flip both relationships) Action<A> > Action<B> => Action<Action<A>> < Action<Action<B>> (2) 把(1)和(2)放在一起,我们有: ,-------------(1)--------------. A < B => Action<A> > Action<B> => Action<Action<A>> < Action<Action<B>> (4) `-------------------------------(2)----------------------------' 但是我们的培训师< T>代表实际上是一个Action< Action< T>: Trainer<T> == Action<Action<T>> (3) 所以我们可以重写(4)为: A < B => ... => Trainer<A> < Trainer<B> – 根据定义,培训师是协调的. 简而言之,应用动作两次,我们得到对抗方差,即类型之间的关系被翻转两次(见(4)),所以我们回到协方差. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |