您的位置:首页 > 编程语言 > C#

c# 逆变 协变的理解

2015-06-16 14:54 495 查看
逆变和协变是C# 4.0出来的,个人认为这是对泛型的扩充,让C#的语法更加灵活,方便重用。只有泛型接口和泛型委托可以是协变的或逆变的。

泛型中有out in关键字,用于定义此泛型是遵守逆变还是协变。out限制了泛型只能用于返回值,in限制了泛型只能用于参数。

之前的泛型是可以指定对某一类操作,但是无法把类的子类,父类赋值转换。有了逆变和协变,实现了泛型类的父类子类的转换。

协变 (covariant)关键字是out,out限制了泛型只能用于返回值

示例代码如:
public interface IEnumerable<out T>

public static void Main()

{

Dog aDog = new Dog();

Animal aAnimal = aDog;

IEnumerable<Dog> someDogs = new List<Dog>();

IEnumerable<Animal> someAnimals = someDogs;

}

现在我们有Animal父类,Dog, Cat子类

public class Animal
{
public string type;

public Animal()
{
type = "Animal";
}
}

public class Dog : Animal
{
public Dog()
{
type = "dog";
}
}

public class Cat : Animal
{
public Cat()
{
type = "Cat";
}
}
如果我们使用List<T>泛型,那我们在List<Animal>和List<Cat>是不能互相转换的。下面的代码是编译不通过的

List<Animal> animalList = new List<Dog>();
如果要实现这个转换必须要使用如下的方法

animalList = dogList.Select(o => (Animal)o).ToList();


但现在我们有这样的方法

public void PrintAnimals(IEnumerable<Animal> animals)
{
foreach (var item in animals)
{
Console.WriteLine(item.type);
}
}
就可以能传递List<Cat>了, 也能传递List<Animal>,因为IEnumerable<out T>有out标记,表示可以协变,所以编译通过。但是在内部,IL还是帮我做了一个个元素依次转换

的工作。这样可以减少了我们的代码量,让程序更灵活。

逆变(contravariant)关键字是in,in限制了泛型只能用于参数
下面以Action<in T>为例

public delegate void Action<in T>

public static void Main()

{

Action<Animal> actionAnimal = new Action<Animal>(a => {/*让动物叫*/ });

Action<Dog> actionDog = actionAnimal;

actionDog(aDog);

}

编译通过,因为 Action支持逆变,类型向下转换

作用:我个人肤浅的理解,之前的泛型是可以指定对某一类操作,但是无法把类的子类,父类赋值转换。有了逆变和协变,实现了泛型类的父类子类的转换。目的是为了增加语言的灵活性和能力。使泛型和委托的功能更加强大。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c# 泛型 c# 4.0