协变和逆变是一个不太好理解的东西。
简单说,泛型委托希望在类型定义上能够通用基类和派生类,即用基类(派生类)类型定义的泛型变量,可以赋值给用派生类(基类)定义的泛型变量,实现互通互用。
一、协变只能用在返回值上,delegate T Func <out T> ();
,
如果我们定义一个基类一个派生类:
public class Animal
{}
public class Dog : Animal
{}
那么派生类委托变量赋值给基类委托变量是可以的:
delegate T Func <out T> ();
static void Main(string[] args)
{
Func<Dog> makedog = Makedog;
Func<Animal> makeanimal = makedog;
makeanimal();
}
static Dog Makedog()
{
Console.WriteLine("success!");
return new Dog();
}
但基类委托变量反过来不能赋值给派生类委托变量:
delegate T Func <out T> ();
static void Main(string[] args)
{
Func<Animal> makeanimal = MakeAnimal;
Func<Dog> makedog = makeanimal;//编译错误
makedog();
}
static Animal MakeAnimal()
{
Console.WriteLine("success!");
return new Dog();
}
二、逆变只能用在参数上,delegate void Func <in T> (T para);
和协变相反,基类委托变量可以赋值给派生类变量:
delegate void Func<in T>(T a);
static void Main(string[] args)
{
Func<Animal> makeanimal= MakeAnimal;
Func<Dog> makedog = makeanimal;
makedog(new Dog());
}
static void MakeAnimal(Animal a)
{
Console.WriteLine("success!");
}
但派生类委托变量不能赋值给基类委托变量。
delegate void Func<in T>(T a);
static void Main(string[] args)
{
Func<Dog> makedog = Makedog;
Func<Animal> makeanimal = makedog;//编译错误
makeanimal(new Animal());
}
static void Makedog(Dog a)
{
Console.WriteLine("success!");
}
三、不可能在一个类型定义上同时使用协变和逆变
delegate T Func< out T> (T para);//编译错误
delegate T Func< in T> (T para);//编译错误
只能分别定义:
delegate T Func< out T,in S> (S para);