一个简单例子理解C#的协变和逆变
2017-11-23 10:22
615 查看
关于协变逆变,SolidMango的解释是比较可取的。有了协变,比如,在需要返回IEnumerable<object>类型的时候,可以使用IEnmerable<string>来替代;有了逆变,比如,在需要接收IComparable<string>类型形参方法中,可以使用IComparable<object>类型实参来替代。
协变
先来体会协变。有2个具有继承关系的父类和子类。
public class Animal { public string Name { get; set; } } public class Dog : Animal { public Dog(string dogName) { Name = dogName; } }
现在有一个帮助类的方法的形参类型是父类集合IEnumerable<Animal>。
public class MyHelper { public void PrintAnimalNames(IEnumerable<Animal> animals) { foreach (var animal in animals) { Console.WriteLine(animal.Name); } } }
有了协变,可以在PrintAnimalNames方法中传入IEnumerable<Dog>类型的实参替代IEnumerable<Animal>类型。
static void Main(string[] args) { List<Dog> dogs = new List<Dog>() { new Dog("小狗petty"), new Dog("小狗lily") }; //协变 IEnumerable<Animal> animals = dogs; MyHelper myHelper = new MyHelper(); myHelper.PrintAnimalNames(animals); Console.ReadKey(); }
可见,在方法中基于基类接口类型的形参,调用该方法的时候可以传入派生类接口类型的实参。
逆变
再来体会逆变。依然是2个具有继承关系的父类和子类。
public class Animal { public string Name { get; set; } public int Age { get; set; } } public class Cat : Animal { public Cat(string catName, int catAge) { Name = catName; Age = catAge; } }
现在,我们想比较基类Animal的两个实例,为此,有必要专门写一个类让他实现IComparer<Animal>接口。
public class AnimalSizeComparator : IComparer<Animal> { public int Compare(Animal x, Animal y) { if (x != null && y != null) { if (x.Age > y.Age) { return 1; } else if (x.Age == y.Age) { return 0; } else { return -1; } } else { return -1; } } }
在帮助类中的方法中,针对Cat进行比较,方法接收IComparer<Cat>类型的形参。
public class MyHelper { public void CompareCats(IComparer<Cat> catComparer) { var cat1 = new Cat("小猫1",1); var cat2 = new Cat("小猫2",2); if (catComparer.Compare(cat2, cat1) > 0) { Console.WriteLine("小猫2胜出"); } else { Console.WriteLine("小猫1胜出"); } } }
有了逆变,客户端调用MyHelper的CompareCats方法时,可以传入IComparer<Animal>类型的实参。
IComparer<Animal> animalComparer = new AnimalSizeComparator(); MyHelper myHelper = new MyHelper(); myHelper.CompareCats(animalComparer); Console.ReadKey();
可见,在方法中基于派生类接口类型的形参,调用该方法的时候可以传入基类接口类型的实参。
总结:在本篇的场景中,派生类接口替代父类接口,称之为协变;父类接口代替派生类接口,称之为逆变。
以上动图由“图斗罗”提供
相关文章推荐
- c#打包文件解压缩 C#中使用委托、接口、匿名方法、泛型委托实现加减乘除算法 一个简单例子理解C#的协变和逆变 对于过长字符串的大小比对
- 一个简单例子理解C#的协变和逆变
- 一个简单例子理解C#的协变和逆变
- c#中子线程控制进度条的一个简单例子
- 一个简单的C#多线程间同步的例子
- 深入理解 C# 协变和逆变
- C#用存储过程的一个简单例子
- 一个简单的C#多线程间同步的例子
- 对Jena的简单理解和一个例子
- 用一个简单的例子来理解python高阶函数
- 通过一个小例子来简单理解C语言中的内存空间管理
- 一个极其简单的在线C#IDE例子
- 一个简单的C#多线程间同步的例子
- 原创 导弹能否摧毁目标?一个简单的例子说明c# 中property(性质)的用法
- c#中子线程控制进度条的一个简单例子
- c#中子线程控制进度条的一个简单例子
- 深入理解 C# 协变和逆变
- 一个C# 事件的简单例子
- C# Remoting的一个简单例子
- C#中子线程控制进度条的一个简单例子