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. idea没有import project解决办法

    参考:https://blog.csdn.net/zengxiaosen/article/details/52807540

  2. ZeroTier 局域网组建工具

    无公网IP通过ZeroTier实现内网穿透 需求:想要在公司访问家里内网NAS,或是在家里访问公司服务 有固定的公网IP或动态的公网IP:常见的方案动态域名解析做端口转发方式等 无公网IP:常见的实现 ...

  3. 【 JdbcUtils 】mysql数据库查询

    JdbcUtils package k.util; import java.sql.*; import java.util.ArrayList; import java.util.HashMap; i ...

  4. Android开发实例之miniTwitter登录界面的实现

    原文: http://www.jizhuomi.com/android/example/134.html 本文要演示的Android开发实例是如何完成一个Android中的miniTwitter登录界 ...

  5. vue-cli 手脚架mock虚拟数据的运用,特别是坑!!!

    1.现在基本的趋势就是前后分离,前后分离就意味着当后台接口还没完成之前,前端是没有接口可以拿来调用的 ,那么mock虚拟数据就很好的解决了这一问题,前端可以直接模拟真实的数据AJAX请求! 运用 步骤 ...

  6. webservice之实现天气预报

    前通过传智的视频自学了webservice的基本使用,也了解到webservice就是一种跨编程语言和跨操作系统平台的远程调用技术. 对于这些理论知识在这里也不再做过多的解释,本次主要就是记录与分享使 ...

  7. 63 滑动窗口的最大值 &&front(),back()操作前一定要判断容器的尺寸不能为0

    给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值.例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6, ...

  8. Xcode Edit Schemes

    关于本文:有关“Xcode Edit Schemes”的设置,还是有很大的学问的.由于时间关系,我一点一点的补充. 1.在开发的时候,至少将Run的Build Configuration设置为Debu ...

  9. Java中Comparator的使用

    在某些特殊情况,我们需要对一个对象数组或集合依照对应的属性排序:此时,我们就可以用Comparator接口处理. 上代码 TestComparaTo 类 package com.test.interf ...

  10. 初始化加载和导航时脚本执行的函数(初始化脚本执行环境)page.evaluateOnNewDocument

    /** * Copyright 2017 Google Inc., PhantomJS Authors All rights reserved. * * Licensed under the Apac ...