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. JS 瀑布流效果

    JS瀑布流效果 <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> < ...

  2. 使用TortoiseGit处理代码冲突

    使用TortoiseGit处理代码冲突  https://www.cnblogs.com/jason-beijing/p/5718190.html 场景一  user0 有新提交 user1 没有pu ...

  3. java 实现用户自由选择字段实现导出EXCEL表格

    package com.thinkgem.jeesite.common.utils.excel; import java.io.File; import java.io.OutputStream; i ...

  4. 字典NSDictionary和NSMutableDictionary的使用

    简介:字典是一种数据结构,字典里面的每一个元素,是一个key-value(键值对),key和value都是对象类型.同NSArray一样,里面的对象不用保持一致性. NSDictionary 1.字面 ...

  5. 吴裕雄--天生自然HADOOP操作实验学习笔记:hbase简介

    实验目的 了解hbase的概念 通过安装hbase了解hbase的原理 了解hbase与hadoop的关系 复习hadoop和zookeeper的运行 实验原理 hbase是bigtable的开源山寨 ...

  6. 四、java基础-面向过程_对象_类中可出现的因素

    1.面向过程和面向对象区别: 1)面向过程:开发一个应用程序.一个项目,必须先了解整个过程,了解各个步骤.模块间的因果关系,使的面向过程方式去开发程序时,代码和代码之间的关联程度是非常强.所以其中任何 ...

  7. 「Luogu P3820 小D的地下温泉」

    这道题的考点比较多. 前置芝士 BFS(DFS),这两种算法在这道题中并没有什么特别突出的地方,基本就是自己看心情写(本文以DFS为准,所以我心情是好是坏呢?) 连通块,可以将每一个温泉看作一个连通块 ...

  8. SQL语言的四种类型

    SQL语言共分为四大类:数据查询语言DQL,数据操纵语言DML,数据定义语言DDL,数据控制语言DCL. 1. 数据查询语言DQL 数据查询语言DQL基本结构是由SELECT子句,FROM子句,WHE ...

  9. Lesson 6 The sporting spirit

    How does the writer describe sport at the international level? I am always amazed when I hear people ...

  10. JdbcTemplate常用方法

    JdbcTemplate简介 JdbcTemplate是Spring JDBC的核心类,借助该类提供的方法可以很方便的实现数据的增删改查. Spring对数据库的操作在jdbc上面做了深层次的封装,使 ...