12 泛型

使用值类型作为参数的泛型容器,传入值类型的参数时,不需要进行装箱

12.1 FCL中的泛型

System.Array中提供了很多泛型方法

  1. AsReadOnly
  2. BinarySearch
  3. ConvertAll
  4. Exists
  5. Find
  6. FindAll
  7. FindIndex
  8. FindLast
  9. FindLastIndex
  10. ForEach
  11. IndexOf
  12. LastIndexOf
  13. Resize
  14. Sort
  15. TrueForAll

12.2 泛型基础结构

12.2.1 开放类型和封闭类型

  1. 具有泛型类型参数的类型成为开放类型

    1. CLR禁止构建开放类型的实例
  2. 为所有类型参数传递了具体类型,则成为封闭类型

    2. 使用不同参数创建的封闭类型,静态成员不同享

12.2.3 泛型类型的同一性

使用using关键字来创建一个类的别名

using DataList = List<Data>;
// 返回true
typeof(DataList) == typeof(List<Data>);

12.2.4 代码爆炸

  1. 使用引用类型的泛型类共享一份代码
  2. 使用值类型的泛型类由编译器生成独一份的代码

12.5 委托和接口的逆变和协变泛型类型实参

泛型委托

泛型委托的泛型类型可以标记为你变量和协变量,默认为不变量

  1. 不变量(invariant):默认,参数类型不可变
  2. 逆变量(contravariant):可以变为子类,只能作为输入
  3. 协变量(covariant):可以变为基类,只能作为输出
delegate TResult Func<in T, out TResult>(T arg);

Func<object, ArgumentException> fn1 = null;
// 可以赋值给另一种使用不同类型参数的泛型委托
Func<string, Exception> fn2 = fn1; // 这是错的
fn1 = fn2;

这也很好理解,Func<string, Exception>的参数和输出是兼容Func<object, ArgumentException>的,例如下面的程序展示的那样:

ArgumentException Func1(object arg) {
...
}
Exception Func2(string arg) {
return Func1(arg);
}

在Func2中调用Func1是OK的,参数可以隐式转化为其基类类型,而反过来则是不对的,不能隐式转为其子类类型。

泛型接口

泛型接口的类型参数也可以声明为逆变量或协变量

interface IWhatTheFuck<in T, out TResult> {
TResult Func(T arg);
} IWhatTheFuck<object, ArgumentException> if1 = null;
IWhatTheFuck<string, Exception> if2 = null; if2 = if1; // 通过编译
if1 = if2; // 编译失败

值类型

值类型作为模板参数时不能逆变或协变(涉及装箱和拆箱)。

12.6 泛型方法

如果普通方法和泛型方法同时匹配一个调用,编译器优先适配普通方法

12.7 泛型和其他成员

属性,索引器,事件,操作符方法,构造器,终结器本身不能有类型参数,但可以使用类的泛型参数

12.8 可验证性和约束

这样的函数无法通过编译

static T Min<T>(T o1, T o2) {
if (o1.CompareTo(o2) < 0) return o1;
return o2;
}

通过添加约束

static T Min<T>(T o1, T o2) where T : IComparable<T> {
if (o1.CompareTo(o2) < 0) return o1;
return o2;
}
  1. 通过泛型约束无法重载
  2. 通过参数个数可以重载
  3. 重写虚泛型方法时,所有的约束会继承,不能添加新的约束

主要约束

  1. 主要约束可以是除了这些类型之外的引用类型:

    1. Object
    2. Array
    3. Delegate
    4. MultiCastDelegate
    5. ValueType
    6. Enum
    7. Void
  2. 指定了主要类型之后,类型参数只能是主要类型或者其子类。
  3. 有两种特殊的主要约束:
    1. class:包括了class,interface,delegate,array
    2. struct:所有的值类型,包括了一个默认的无参数构造函数

次要约束

  1. 指明需要实现的多个接口
  2. 指明多个类型参数之间的关系
    static List<TBase> ConvertIList<T, TBase>(IList<T> list) where T : TBase {
    List<TBase> baseList = new List<TBase>(list.Count);
    for (int i = 0; i < list.Count; i++) {
    baseList.Add(list[i]);
    }
    }

构造函数约束

  1. 约束中可以包含一个构造器约束
  2. 指定类型可以有一个public,无参数的构造函数
  3. 主要约束为值类型,无需指定构造函数约束

其他情况

  1. 隐式转型模板函数中的未定类型变量是非法的,除非在约束中指定过了
  2. 使用defaut(T)来初始化一个未定类型的变量
    1. 为引用类型初始化为null
    2. 为值类型初始化内存为0
  3. 未定类型变量与null进行比较是否相等,编译器不会报错,如果是值类型作为参数,编译器判断为不等
    void func<T>(T o) {
    if (o == null) {
    // 如果T是引用类型,判断成立
    // 如果T是值类型,判断不成立
    // 但是编译器不会报错
    }
    }
  4. 相同类型的泛型类型变量之间不能直接比较是否相等
    void func<T>(T a, T b) {
    if (a == b) { ... } // 编译不通过
    if (EqualityComparer<T>.Default.Equals(a, b)) { ... } // 编译通过
    }
  5. 泛型类型变量无法作为操作数使用
    void func<T>(T a, T b) {
    var c = a + b; // 编译不通过
    }

总结

  1. C#的泛型比C++模板是更好的存在

    1. 通过各种约束,可以直接编译泛型函数\类
    2. 模板需要实例化,导致代码爆炸,各模块\编译单元的实例化模板类还不通用,需要
      1. template class std::vector<int>;显式实例化
      2. template class __declspec(dllexport) std::vector<int>;实例化导出实例化的模板类
      3. extern template class std::vector<int>;引用别处的实例化模板类
  2. C#函数是如何调用的?
    1. 如果像C++那样,直接绑定函数地址,那么对于不同参数的模板类,类型成员函数的参数地址是不同的,如何做到不同参数的模板共享一份代码的呢?
    2. 如果模板类没有源码,怎样用dll中的开放类(已经编译成IL),生成一个参数为值类型的封闭类呢?

.NET via C#笔记12——泛型的更多相关文章

  1. Ext.Net学习笔记12:Ext.Net GridPanel Filter用法

    Ext.Net学习笔记12:Ext.Net GridPanel Filter用法 Ext.Net GridPanel的用法在上一篇中已经介绍过,这篇笔记讲介绍Filter的用法. Filter是用来过 ...

  2. 《CLR via C#》读书笔记 之 泛型

    第十二章 泛型 2014-06-15 初始泛型 12.3 泛型基础结构 12.3.1 开放类型与封闭类型 12.3.2 泛型类型和继承 12.3.3 泛型类型同一性 12.3.4 代码爆炸 12.6 ...

  3. 机器学习实战 - 读书笔记(12) - 使用FP-growth算法来高效发现频繁项集

    前言 最近在看Peter Harrington写的"机器学习实战",这是我的学习心得,这次是第12章 - 使用FP-growth算法来高效发现频繁项集. 基本概念 FP-growt ...

  4. C#&java重学笔记(泛型)

    C#部分: 1.泛型的出现主要用于解决类.接口.委托.方法的通用性,通过定义泛型类.接口.委托.方法,可以让不同类型的数据使用相同运算规则处理数据,方便了开发. 2.利用System.Nullable ...

  5. TypeScript笔记[5]泛型+Dictionary 转

    TypeScript笔记[5]泛型   在C++.C#.Java等主流编程语言中,一般对泛型编程提供了支持.合理利用泛型,可以提高开发效率.提升代码质量. 例如在C++编程语言中,常常利用下面的结构表 ...

  6. SQL反模式学习笔记12 存储图片或其他多媒体大文件

    目标:存储图片或其他多媒体大文件 反模式:图片存储在数据库外的文件系统中,数据库表中存储文件的对应的路径和名称. 缺点:     1.文件不支持Delete操作.使用SQL语句删除一条记录时,对应的文 ...

  7. JAVA自学笔记12

    JAVA自学笔记12 1.Scanner 1)JDK5后用于获取用户的键盘输入 2)构造方法:public Scanner(InputStream source) 3)System.in 标准的输入流 ...

  8. golang学习笔记12 beego table name `xxx` repeat register, must be unique 错误问题

    golang学习笔记12 beego table name `xxx` repeat register, must be unique 错误问题 今天测试了重新建一个项目生成新的表,然后复制到旧的项目 ...

  9. Spring MVC 学习笔记12 —— SpringMVC+Hibernate开发(1)依赖包搭建

    Spring MVC 学习笔记12 -- SpringMVC+Hibernate开发(1)依赖包搭建 用Hibernate帮助建立SpringMVC与数据库之间的联系,通过配置DAO层,Service ...

随机推荐

  1. Python环境搭建-5 代码编辑器

    代码编辑器 Python解释器.pip工具箱和virtuanlenv虚拟环境都安装好了后,基本的Python环境就搭建好了,可以开始我们的"搬砖"之旅了.但是现在还缺一个好用的编辑 ...

  2. SpringBoot之日志记录-专题四

    SpringBoot之日志记录-专题四 六.日志管理 6.1使用log4j记录日志 6.1.2新建log4j配置文件 文件名称log4j.properties #log4j.rootLogger=CO ...

  3. CSP-J2019 加工零件

    Background: 之前 $noip $死了,泥萌都说 \(noip SPFA\) 了,现在 \(noip\) 复活了,所以 \(SPFA\) 也复活了. (注:这里的 \(noip\) 跟 \( ...

  4. Day11-G - Calendar Game HDU - 1079

    Adam and Eve enter this year’s ACM International Collegiate Programming Contest. Last night, they pl ...

  5. SpringBoot 处理异常的几种常见姿势

    SpringBoot 处理异常的几种常见姿势 1. 使用 @ControllerAdvice 和 @ExceptionHandler 处理全局异常 这是目前很常用的一种方式,非常推荐.测试代码中用到了 ...

  6. java程序员,英语那点事

    本文选自<Java程序员,上班那点事儿>有时候如果应聘到了一个有外资背景的公司或者这个公司的很多人都有海外或外资工作背景时,你 也许还会用到一些日常工作交流时候的词汇.        比如 ...

  7. Android LowMemoryKiller原理分析

    copy from : http://gityuan.com/2016/09/17/android-lowmemorykiller/ frameworks/base/services/core/jav ...

  8. vue项目真机测试

    1.在项目中重启命令行运行ipconfig(如果是ios系统运行ifconfig)获取到项目在本机运行的ip地址 2.在项目的package.json中修改允许访问ip地址(--host 0.0.0. ...

  9. jforum发表文章和回复文章显示中文乱码问题

    jforum安装时,在数据库创建jforum数据库的时候,设置了字符集(CREATE DATABASE jforum DEFAULT CHARACTER SET utf8 COLLATE utf8_g ...

  10. Linux学习计划中遇到的问题记录

    随时更新 Linux安装到网络联通遇到的问题及解决办法 1.命令区分大小写 2..网络连通 ping本地 地址遇到问题 解决办法: https://blog.csdn.net/qq_42074075/ ...