从C#2.0开始,就提出了委托的协变与逆变的概念,在CSDN中不少文章都解释他们,但是比较难以理解。本文尝试以简单的表述,让大家快速理解这两个概念。
初步印象
首先,协变和逆变都是为了C#中的委托(delegate)的参数列表和返回类型有更好地适用性而提出的。简单地说,就是当参数列表和返回的数据类型都可以用类的派生的概念进行扩展。下面看具体的示例。
委托协变
- 我们定义 Person类和Student类,其中Student类由Person类派生。
- 我们定义了以下两个方法:
public Person NewPerson(){
return new People();
}
public Student NewStudent(){
return new Student();
}
- 我们定义一个委托:
delegate Person Create();
根据以上的描述,可以肯定的是这个代理是可以调用NewPerson()
方法的,但是可以调用NewStudent()
方法吗?答案是C#1.0不可以,因为返回的数据类型不一样。但是从C#2.0开始就可以了,因为这就是委托的协变,即返回参数的数据类型如果是委托返回类型的派生类,就可以调用 。
以下是标准的委托的协变的定义:
允许所调用方法的返回类型可以是委托的返回类型的派生类型,当委托方法的返回类型具有的派生程度比委托签名更大时,就称为协变委托方法。
委托逆变
逆变的概念与协变其实很类似,只不过它是用来说明参数列表的,请看下面的示例:
- 我们同样定义 Person类和Student类,其中Student类由Person类派生。
- 我们定义了以下两个方法:
public void ProcessPerson(Person p){ }
public void ProcessStudent(Student s){ }
- 我们定义一个委托:
delegate void Process(Person p);
类似的,在C#1.0中,Process代表只能代理 ProcessPerson(Person p)
,而从C#2.0开始,ProcessStudent(Student s)
也可以代理了,参数列表中的这种派生关系的变化称之为委托的逆变。
以下是标准的委托的逆变的定义:
允许将带有派生参数的方法用作委托时,当委托方法签名具有一个或多个参数,并且这些参数的类型派生自方法参数时,就称为逆变委托方法。
小结
所以C#2.0开始,引入的委托的协变和逆变的目的,就是为了扩展委托的调用范围。简单的地,就是只要是参数列表或返回值的数据类型可以是相应数据类型的派生类,即 is a 关系。