C#中的协方差是什么? (或,协方差:例如)

前端之家收集整理的这篇文章主要介绍了C#中的协方差是什么? (或,协方差:例如)前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
协方差(粗略地)在使用它们的复杂类型中镜像“简单”类型的继承的能力.
例如.我们总是可以把猫的一个例子视为动物的一个例子.复杂类型< Cat>可以被视为ComplexType< Animal>如果ComplexType是协方差的.

我想知道:协方差的“类型”是什么,它们如何与C#相关(是否支持?)
代码示例将是有帮助的.

例如,一种类型是返回类型协方差,由Java支持,但不是C#.

我希望有功能的编程人员也可以进来,

解决方法

这是我能想到的:

更新

阅读建设性意见和Eric Lippert指出(和写的)大量文章后,我改进了答案:

更新了阵列协方差的破坏
>添加“纯”委托方差
>从BCL增加了更多的例子
>添加了对深入解释概念的文章链接.
>增加了关于高阶函数参数协方差的全新部分.

返回类型协方差:

C#中不支持Java(> = 5)[1]和C [2](Eric Lippert解释why notwhat you can do about it):

class B {
    B Clone();
}

class D: B {
    D Clone();
}

界面协方差[3]支持C#

BCL将通用的IEnumerable接口定义为协变量:

IEnumerable<out T> {...}

因此,以下示例是有效的:

class Animal {}
class Cat : Animal {}

IEnumerable<Cat> cats = ...
IEnumerable<Animal> animals = cats;

请注意,IEnumerable的定义是“只读” – 您不能向其添加元素.
与IList< T>的定义相反,其可以被修改.使用.Add():

public interface IEnumerable<out T> : ...  //covariant - notice the 'out' keyword
public interface IList<T> : ...            //invariant

代表协方差方法[4]支持C#

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

}

“纯”代表协方差[5 - pre-variance-release article]支持C#

没有参数并返回某些东西的委托的BCL定义是协变的:

public delegate TResult Func<out TResult>()

这允许以下内容

Func<Cat> getCat = () => new Cat();
Func<Animal> getAnimal = getCat;

数组协方差 – 支持C#,破碎的方式[6] [7]

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

最后 – 令人惊讶和有点头脑弯曲
委托参数协方差(yes,即协方差) – 用于高阶函数

承担一个参数并且不返回任何事件的委托的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);

输出证明这是有效的:

Training Cat to ignore you… done!

为了理解这个,一个笑话是有序的.

A linguistics professor was lecturing to his class one day.
“In English,” he said,“a double negative forms a positive.
However,” he pointed out,“there is no language wherein a double positive can form a negative.”

A voice from the back of the room piped up,“Yeah,right.”

这与协方差有什么关系?

让我尝试一下餐巾纸展示.

动作< 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)),所以我们回到协方差.

猜你在找的C#相关文章