上节讲到了泛型,这节延申一下,讲一下变体。

变体(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)的更多相关文章

  1. 自然语言19.1_Lemmatizing with NLTK(单词变体还原)

    QQ:231469242 欢迎喜欢nltk朋友交流 https://www.pythonprogramming.net/lemmatizing-nltk-tutorial/?completed=/na ...

  2. 【Visual Lisp】变体与安全数组

    (vlax-make-variant) ;;创建一个未初始化的变体 ;;01.整型值变体(setq myvar (vlax-make-variant 10)) ;;创建整型值变体,返回 #<va ...

  3. labview 变体数据类型

    变体数据类型是LabVIEW中多种数据类型的容器.将其它数据转换为变体时,变体将存储数据和数据的原始类型,保证日后可将变体数据反向转换. 例如,如将字符串数据转换为变体,变体将存储字符串的文本,以及说 ...

  4. Bootstrap 标签的变体 实例样式

    Bootstrap 标签样式,代码如下: <!DOCTYPE html> <html> <head> <title>Bootstrap 实例 - 标签的 ...

  5. Odoo / PS Cloud12版本中,产品变体功能如何使用

    场景: 产品:陶瓷马克杯 产品颜色变体:红色.蓝色.白色 产品尺寸变体:10CM.12CM.15CM 每个变体都有不同价格维度 odoo / PS Cloud 专业实施开发 EMAIL:1715860 ...

  6. 二叉查找树及B-树、B+树、B*树变体

    动态查找树主要有二叉查找树(Binary Search Tree),平衡二叉查找树(Balanced Binary Search Tree), 红黑树 (Red-Black Tree ), 都是典型的 ...

  7. (转) 干货 | 图解LSTM神经网络架构及其11种变体(附论文)

    干货 | 图解LSTM神经网络架构及其11种变体(附论文) 2016-10-02 机器之心 选自FastML 作者:Zygmunt Z. 机器之心编译  参与:老红.李亚洲 就像雨季后非洲大草原许多野 ...

  8. 完全图解RNN、RNN变体、Seq2Seq、Attention机制

    完全图解RNN.RNN变体.Seq2Seq.Attention机制 本文主要是利用图片的形式,详细地介绍了经典的RNN.RNN几个重要变体,以及Seq2Seq模型.Attention机制.希望这篇文章 ...

  9. Delphi 变体数组 Dataset Locate 查找定位

    Format 函数 Delphi 支持“开参数”和动态数组,变体数组,使用时的语法类似 Delphi 中的集合:采用两个方括号把不同类型的变量括起来(这太方便了啊),也可以采用声明一个 TVarRec ...

随机推荐

  1. [源码解析] 并行分布式框架 Celery 之架构 (2)

    [源码解析] 并行分布式框架 Celery 之架构 (2) 目录 [源码解析] 并行分布式框架 Celery 之架构 (2) 0x00 摘要 0x01 上文回顾 0x02 worker的思考 2.1 ...

  2. frp实现内网穿透

    frp实现内网穿透 目标 通过外网访问内网设备,本文中实现通过手机的移动流量,可以访问到树莓派设备 设备准备 需要被访问的设备(本文中使用Raspberry Pi`).公网IP设备(本文中使用阿里云 ...

  3. Amundsen在REA Group公司的应用实践

    REA Group是一家专门面向房地产与实业资产的跨国数字广告公司. 他们主要为消费者提供房地产购买.出售与租赁服务,同时发布各类房产新闻.装修技巧以及生活方式层面的内容.每一天,都有数百万消费者访问 ...

  4. Android 在活动中使用 Menu

    •前行必备--创建 menu 首先,新建一个项目,选择 Empty Activity 选项,并命名为 Test Menu: 这样 Android Studio 自动为我们新建 MainActivity ...

  5. 写个小程序01 | 注册微信小程序

    出于兴趣和学习目的,我想自己做一个基于"子弹笔记(Bullet Journal)"的小程序.由于个人开发经验很有限,只在课程作业中写过 web 前端,所以也不知道多久能写出来(逃) ...

  6. 单链表c语言实现的形式

    包括初始化,创建,查询,长度,删除,清空,销毁等操作 代码如下: #include<stdio.h> #include<stdlib.h> //定义单链表的数据类型 typed ...

  7. Elasticsearch集群升级指引

    目录 背景 第一部分 版本升级指引 第二部分 升级方法和具体步骤 总结 参考文献及资料 背景 Elasticsearch集群的版本升级是一项重要的集群维护工作.本篇文章参考官方文档,将详细介绍相关细节 ...

  8. 免费开源的客服系统 Linux 服务器环境安装部署过程

    最近因为项目需要,要找一款在线客服系统集成在 APP 中使用,而且涉及到生意开单,客服系统必须稳定可靠.另外甲方要求,必须支持 Linux 服务器环境. 我们以 Ubuntu 18.04 为例把安装部 ...

  9. nacos下载慢吗?来这里

    https://gitee.com/soul_PreCoder/springcloudalibab/repository/archive/master.zip

  10. Vue 中的 mixin,component,render,hoc

    在项目中,一般我们经常会基于一套现有组件库进行快速开发,但是现实中往往需要对组件库进行定制化改造二次封装 混入(mixin) vue 官方介绍 混入 (mixin) 提供了一种非常灵活的方式,来分发 ...