一个简单例子理解C#的协变和逆变
c# 一个 简单 理解 例子 逆变 协变
2023-09-11 14:16:51 时间
关于协变逆变,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# Project : KsPlanMon
- C# winform DataGridView
- C# .NET想要另存一个项目,sln文件丢了怎么办
- C# winform 学习(一)
- C# 操作Excel之旁门左道 [ C# | Excel ]
- EQueue - 一个C#写的开源分布式消息队列的总体介绍
- EQueue - 一个纯C#写的分布式消息队列介绍2
- 数字图像处理 使用C#进行图像处理二
- C# 如何识别一个字符串是否Json格式
- C# 异常处理(Catch Throw)IL分析
- C# 将一个对象转换为指定类型
- C#如何将两个XmlDocument合并为一个XmlDocument
- atitit.木马病毒webshell的原理and设计 java c# .net php.
- Atitit.sql ast 表达式 语法树 语法 解析原理与实现 java php c#.net js python
- C# 数据类型
- c#一个简单的实例告诉你,多继承还可以这么来
- C# 获得Excel工作簿Sheet页面(工作表)集合的名称
- C#使用xpath找到一个节点
- CSharpGL(0)一个易学易用的C#版OpenGL
- C#+无unsafe的非托管大数组(large unmanaged array in c# without 'unsafe' keyword)
- C#上传文件
- (68)C#里怎么样提供一个有窗口显示进度条的拷贝目录的功能
- C# 实现:将一个文件夹下的.png图片全部移动到另一个文件夹
- C#计算一个数的N次幂(包含负数)