C# 变体(variance)
上节讲到了泛型,这节延申一下,讲一下变体。
变体(variance)是协变(convariance)和抗变(也说逆变contravariance)的统称。这个概念在.net 4中引入,在.net 2.0中就可以使用,但是比较麻烦,.net 4将这一概念封装成了特性。
讲变体之前,我们先来复习一下多态性。请看如下代码:
class Animals
{
public virtual void Say(){}
}
class Cat : Animals
{
public override void Say()
{
Console.WriteLine("小猫喵喵叫");
}
}
class Dog : Animals
{
public override void Say()
{
Console.WriteLine("小狗汪汪汪");
}
}
interface IAnimals<out T> where T :Animals, new()
{
void InvokeSay();
}
interface IAnimalsType<in T> where T : Animals
{
Type GetType();
}
class AnimalsType<T>:IAnimalsType<T> where T : Animals
{
public Type GetType()
{
return typeof(T);
}
}
class AnimalsAdmin<T> : IAnimals<T> where T : Animals,new()
{
//此处涉及到反射,不清楚反射的读者请留意后期文章
//此处只需知道调用了传入实例类的Say()方法即可
public void InvokeSay()
{
Type type = typeof(T);
T t = new T();
MethodInfo Say = type.GetMethod("Say");
Say.Invoke(t, null);
}
}
有一父类Animals,Cat和Dog继承此类,根据多态性,以下代码是可行的:
Animals cat = new Cat();
Animals dog = new Dog();
有两个接口,分别由两个类继承,先分析其中一个类和接口,下面的代码是编译不过的:
IAnimals<Animals> animals;
animals=new AnimalsAdmin<Dog>();//父类是IAnimals<Dog>
animals= new AnimalsAdmin<Cat>();//父类是IAnimals<Cat>
以上转换,在多态性中看似是可以的,但其实这样的转换不属于多态。多态性是基于类的继承,若两个类没有继承关系,何谈多态,AnimalsAdmin<Dog>和AnimalsAdmin<Cat>的父类和IAnimals<Animals>是平行类型关系,没有继承关系。只有以下代码是可行的:
IAnimals<Animals> animals;
animals=new AnimalsAdmin<Animals>();
而变体,让这样的转换变的可行。
协变:
为了建立他们之间的继承关系,接口IAnimals<T>的类型需要设置为协变,有了协变类型,AnimalsAdmin<Dog>,AnimalsAdmin<Cat>这两个类和IAnimals<Animals>就建立了继承关系(这一点比多态性稍微复杂一些)。那如何设为协变类型呢:
interface IAnimals<out T> where T :Animals, new()
{
void InvokeSay();
}
T前加关键字out即可。我们来看一下运行结果:
微软的API中也有很多协变的例子:例如IEnumerable泛型接口就是协变性的。
抗变:
了解了协变,那么对于抗变,小伙伴们也能猜出是什么意思,协变是向上转换,请分析另一对接口和类,看如下代码:
AnimalsAdmin<Cat> cAdmin = new AnimalsAdmin<Cat>();
Type type = cAdmin.GetAnimalType(new AnimalsType<Animals>());
没有抗变,以上代码显然是不可行的,因为cAdmin.GetAnimalType的参数需要一个AnimalsType<Cat>类型的,为了使这种转换可行,需将IAnimalsType<T>接口设置为抗变类型:
interface IAnimalsType<in T> where T :Animals
{
Type GetAnimalType();
}
在T前加关键字in,我们来看一下运行结果:
抗变在.net Framework中有很多用处,IComparable泛型接口就是抗变类型。
通过变体,我们在面向泛型接口编程的时候,就可以借助多态性很灵活的编码。最后注意两点:设置为协变类型的T,只能用作返回类型和属性get访问器的类型,而设置为抗变类型的T只能用作方法的参数。
本节源码文件位于:
https://github.com/Chunlei-Su/PublicDemo/tree/master/C%23/C%23Senior/Variance(%E5%8F%98%E4%BD%93)
这是我的公众号二维码,获取最新文章,请关注此号
C# 变体(variance)的更多相关文章
- 自然语言19.1_Lemmatizing with NLTK(单词变体还原)
QQ:231469242 欢迎喜欢nltk朋友交流 https://www.pythonprogramming.net/lemmatizing-nltk-tutorial/?completed=/na ...
- 【Visual Lisp】变体与安全数组
(vlax-make-variant) ;;创建一个未初始化的变体 ;;01.整型值变体(setq myvar (vlax-make-variant 10)) ;;创建整型值变体,返回 #<va ...
- labview 变体数据类型
变体数据类型是LabVIEW中多种数据类型的容器.将其它数据转换为变体时,变体将存储数据和数据的原始类型,保证日后可将变体数据反向转换. 例如,如将字符串数据转换为变体,变体将存储字符串的文本,以及说 ...
- Bootstrap 标签的变体 实例样式
Bootstrap 标签样式,代码如下: <!DOCTYPE html> <html> <head> <title>Bootstrap 实例 - 标签的 ...
- Odoo / PS Cloud12版本中,产品变体功能如何使用
场景: 产品:陶瓷马克杯 产品颜色变体:红色.蓝色.白色 产品尺寸变体:10CM.12CM.15CM 每个变体都有不同价格维度 odoo / PS Cloud 专业实施开发 EMAIL:1715860 ...
- 二叉查找树及B-树、B+树、B*树变体
动态查找树主要有二叉查找树(Binary Search Tree),平衡二叉查找树(Balanced Binary Search Tree), 红黑树 (Red-Black Tree ), 都是典型的 ...
- (转) 干货 | 图解LSTM神经网络架构及其11种变体(附论文)
干货 | 图解LSTM神经网络架构及其11种变体(附论文) 2016-10-02 机器之心 选自FastML 作者:Zygmunt Z. 机器之心编译 参与:老红.李亚洲 就像雨季后非洲大草原许多野 ...
- 完全图解RNN、RNN变体、Seq2Seq、Attention机制
完全图解RNN.RNN变体.Seq2Seq.Attention机制 本文主要是利用图片的形式,详细地介绍了经典的RNN.RNN几个重要变体,以及Seq2Seq模型.Attention机制.希望这篇文章 ...
- Delphi 变体数组 Dataset Locate 查找定位
Format 函数 Delphi 支持“开参数”和动态数组,变体数组,使用时的语法类似 Delphi 中的集合:采用两个方括号把不同类型的变量括起来(这太方便了啊),也可以采用声明一个 TVarRec ...
随机推荐
- 部署Angular应用到Github pages
https://jeneser.github.io/blog/2017/08/08/angular-deploying-app-github-pages/ Published: August 08, ...
- 冒泡排序算法的实现(Java)
什么是冒泡排序 冒泡排序(Bubble Sort),是一种计算机科学领域的较简单的排序算法.它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果顺序(如从大到小.首字母从Z到A)错误就把他们交换 ...
- .NET Core 环境变量详解
一.概述 软件从开发到正式上线,在这个过程中我们会分为多个阶段,通常会有开发.测试.以及上线等.每个阶段对应的环境参数配置我们会使用不同的参数.比如数据库的连接字符串,开发环境一般我们都是连接的测试库 ...
- Python基础之数据类型详解
为什么会有数据类型? 在介绍具体的数据类型之前,需要了解为什么需要区分数据类型.我们知道,一个公司会有很多个大的部门,每个部门下又会有许多细分的小部门,构成了公司的完整体系结构.如果把python的数 ...
- Linux 软链接link/ln -s
在Linux中,链接分为软的和硬的,至于两者之间有什么差别,大家可以参考下https://www.ibm.com/developerworks/cn/linux/l-cn-hardandsymb-li ...
- 设计原则:单一职责(SRP)原则
1 什么是单一职责(SRP)原则 单一职责原则的英文是 Single Responsibility Principle,缩写为 SRP.翻译过来就是:一个类或者模块只负责完成一个职责(或者功能). 所 ...
- python基础(六):列表的使用(下)
列表排序的三种方式 sort()方法:原地修改列表的排序方法 注 1:" 默认是升序" ,参数 reverse=True,表示将列表降序. 注 2:" 原地修改列表&qu ...
- Docker系列——InfluxDB+Grafana+Jmeter性能监控平台搭建(三)
在之前系列博文中,已经介绍完了数据采集和数据存储,那数据如何展示呢?所以今天就专门来讲下数据如何展示的问题. 以前博文参考: Docker系列--InfluxDB+Grafana+Jmeter性能监控 ...
- B - 抽屉 POJ - 2356 (容斥原理)
The input contains N natural (i.e. positive integer) numbers ( N <= 10000 ). Each of that numbers ...
- 功能:SpringBoot整合rabbitmq,长篇幅超详细
SpringBoot整合rabbitMq 一.介绍 消息队列(Message Queue)简称mq,本文将介绍SpringBoot整合rabbitmq的功能使用 队列是一种数据结构,就像排队一样,遵循 ...