《CLR.via.C#第三版》第二部分第12章节 泛型 读书笔记(六)

终于讲到泛型了。当初看到这个书名,最想看的就是作者对泛型,委托,反射这些概念的理解。很多人对泛型的理解停留在泛型集合上,刚开始我也是,随着项目越做越多,对待泛型的认识也越来越深刻。

泛型的概念:泛型是一种特殊的类型,它把指定类型的工作推迟到客户端代码声明并实例化类或方法的时候进行。

泛型的优势:源代码保护、类型安全、更加清晰的代码、更佳的性能。

原理:(关键字:开放类型,封闭类型)所有带泛型参数的类型都是一个开放式类型,它不能被实例化(类似接口),在具体使用时生成封闭类型(实际数据类型)。

泛型约束(至多一个主要约束,次要约束无限制):

泛型约束的使用:

        /// <summary>
        /// 未加约束的T可以是任何类型,许多类型没有提供CompareTo方法,没有约束将导致代码不能编译,报"‘T‘不包含‘CompareTo‘的定义"错误
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="o1"></param>
        /// <param name="o2"></param>
        /// <returns></returns>
        private static T Min<T>(T o1,T o2) where T : IComparable<T>
        {
            if (o1.CompareTo(o2) < 0) return o1;
            return o2;
        }

构造器约束:

//因为所有值类型都隐式有一个公共无参构造器。约束要求指定的任何引用类型也要有一个公共无参构造器
internal sealed class ConstructorConstraint<T> where T:new(){
      public static T Factory(){
          return new T();
      }
}

由于泛型类型参数不能指定以下特殊引用类型:System.Object,System.Array,System.Delegate,System.MulticastDelegate,System.ValueType,System.Enum,System.Void,一些实参限制的实现可能要“特殊处理”,如以下使用静态构造器来保证类型是一个枚举类型。

internal sealed class GenericTypeThatRequiresAnEnum<T>{
    static GenericTypeThatRequiresAnEnum(){
        if(!typeof(T).IsEnum){
             throw new ArgumentException("T must be an enumerated type");
        }
    }
}

泛型接口的优势:没有泛型接口,每次视图使用一个非泛型接口来操作一个值类型,都会发生装箱,而且会失去编译时的类型安全性。

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

不变量:意味着泛型类型参数不能更改。(常用)

逆变量:意味着泛型类型参数可以从一个基类更改为该类的派生类。在C#中,用in关键字标记逆变量形式的泛型类型参数。逆变量泛型类型参数只出现在输入位置,比如作为方法的参数。

协变量:意味着泛型类型参数可以从一个派生类更改为它的基类。在C#中,是用out关键字标记协变量形式的泛型类型参数。协变量泛型类型参数只能出现在输出位置,比如作为方法的返回类型。

public delegate TResult Func<in T,out TResult>(T arg);

其它重要认知:

类型实参的指定和继承层次结构没有任何关系--理解这一点,有助于你判断转型的进行。
C#允许使用简化的语法来引用一个泛型封闭类型

using DateTimeList = System.Collections.Generic.List<System.DateTime>;

现在执行下面这行代码时,sameType会被初始化为true:

Boolean sameType = (typeof(List<DateTime>) == typeof(DateTimeList));

CLR支持泛型委托,目的是保证任何类型的对象都能以一种类型安全的方式传给一个回调方法。此外,泛型委托允许任何一个值类型实例在传给一个回调方法时不执行任何装箱处理。

一些验证问题:

1. 泛型类型变量的转型

将一个泛型类型的变量转型为另一个类型是非法的,除非将其转型为另一个约束兼容的类型

private static void CastingType<T>(T obj){
     Int32 x = (Int32)obj;//错误
     String s = (String)obj;//错误
     string s2 = obj as String;//无错误
}

2. 设定默认值

private static void SettingDefaultValue<T>(){
      T temp = default(T);
}

default关键字告诉C#编译器和CLR的JIT编译器,如果T是一个引用类型,就将temp设为null,如果T是一个值类型,就将temp的所有位设为0。

时间: 2024-08-28 14:20:17

《CLR.via.C#第三版》第二部分第12章节 泛型 读书笔记(六)的相关文章

Java 线程第三版 第八章 Thread与Collection Class 读书笔记

JDK1.2引入最有争议性的改变是将集合类默认为不是Thread安全性的. 一.Collection Class的概述 1. 具有Threadsafe 的Collection Class: java.util.Vector(List) 列表集合,通过索引操作. java.util.Stack(List) 继承自Vector,提供LIFO的顺序操作push进入,pop出元素. java.util.Hashtable(Map) 一个简单.无序的key与value的映射. java.util.conc

《CLR.via.C#第三版》第二部分第13章节 接口 读书笔记(七)

这章的书写感觉很普通,是些基础的认知知识. 其中一点的重要认知,泛型接口的好处(其实也是使用泛型的好处之一):编译时类型安全&处理值类型时减少装箱. 再说点书上没有的.本来这些知识我打算另外分类在C#基础里讲的,这里先单独表述下. 接口回调 其实我想不通为什么这本书不讲一下接口回调这个概念,我可不会相信接口回调只在java中用到. 到现在为止,我突然发现,很多编程的基础概念,于面向对象编程的语言来说,都是通用的,但是抱歉,在C#里(相关书籍)居然没有!但我相信你翻阅Java书籍就有很大几率看到这

《CLR.via.C#第三版》第一部分读书笔记(一)

最近开始仔细研读<CLR.via.C#第三版>这本书.读pdf文档确实很累.建议有条件的朋友还是买书看吧. 我的笔记用来记录我对这本书的理解,简化下逻辑,对每个部分我觉得是要点的进行归纳总结.特别基础的东西不会做过多的阐述. 第一部分讲的是CLR基础. 首先还是重新说下CLR的概念:“CLR 是一个可由多种编程语言使用的“运行时”.可用任何编程语言来开发代码,只要编译器是面向CLR的就可以了”.这里要重新解释下“只要编译器是面向CLR的就可以了”这句话.初学者一般不认同.net平台跨语言,或者

三周第二次课(12月26) 3.4 usermod命令 3.5 用户密码管理 3.6 mkpasswd命令

三周第二次课(12月26) 3.4 usermod命令3.5 用户密码管理3.6 mkpasswd命令 usermod命令: 用户和工作组管理: usermod命令用于修改用户的基本信息. usermod命令不允许你改变正在线上的使用者帐号名称. 当usermod命令用来改变user id, 必须确认这名user没在电脑上执行任何程序. 你需手动更改使用者的crontab档. 也需手动更改使用者的at工作档. 采用NIS server须在server上更动相关的NIS设定. 语法: usermo

Android深度探索(卷1)HAL与驱动开发 第二章 搭建Android开发环境 读书笔记

Android深度探索(卷1)HAL与驱动开发 第二章 搭建Android开发环境 读书笔记   本章主要讲解在Ubuntu Linux 下搭建Android开发环境. 1.JDK:从官网下载压缩包,并将其解压缩. Gedit etc/profile 并设置PATH环境变量,记得PATH. 2.搭建Android应用程序开发环境. 安装Android SDK 安装Eclipse 安装ADT 配置ADT 建立AVD 这个步骤是安装Android SDK,步骤与操作与在Windows操作系统下的安装

王爽《汇编语言》第三版 第二章 寄存器

CPU概述 一个典型的CPU由运算器.控制器.寄存器等器件组成,这些器件靠内部总线相连. 内部总线实现CPU内部各个器件之间的联系,外部总线实现CPU和主板上其它器件的联系. 8086CPU有14个寄存器 它们的名称为:AX.BX.CX.DX.SI.DI.SP.BP.IP.CS.SS.DS.ES.PSW. 2.1 通用寄存器 8086CPU所有的寄存器都是16位的,可以存放两个字节. 8086上一代CPU中的寄存器都是8位的: 为保证兼容性,这四个寄存器都可以分为两个独立的8位寄存器使用. 1.

Python核心编程第三版第二章学习笔记

第二章 网络编程 1.学习笔记 2.课后习题 答案是按照自己理解和查阅资料来的,不保证正确性.如由错误欢迎指出,谢谢 1. 套接字:A network socket is an endpoint of a connection across a computer network,Sockets are often represented internally as simple integers, which identify which connection to use. 套接字是网络通信的

《CLR.via.C#第三版》第二部分第4,5章节读书笔记(二)

这两章全是理论性的东西,我觉得不必过于钻牛角尖.理论这东西,只有在长期的实践中去慢慢领悟才会深刻.下面我只写些我认为重要的关键知识. (一)类型转换 知识点:向基类型的转换被认为是一种安全的隐式转换:向派生类型转换时,只能显示转换. 举例: Object o = new Employee(); Employee e = (Employee)o; 重要认知:CLR的类型检查会遍历继承层次结构,用每个基类型去核对指定的类型. 常用代码:(见下方代码段.CLR会检查两次对象的类型): if(o is

《CLR.via.C#第三版》第二部分第8,9章节读书笔记(四)

三种类型的构造方法: 实例构造器(引用类型):实例构造器永远不能被继承(所以方法前没有修饰符):如果类的修饰符为static(sealed和abstract),编译器根本不会在类的定义中生成一个默认构造器. 重要认知:为了使代码“可验证”,类的实例构造器在访问从基类继承的任何字段之前,必须先调用基类的构造器.如果派生类的构造器没有显示调用一个基类构造器,C#编译器会自动生成对默认的基类构造器的调用. 在类中声明的字段,实际在编译器中是转换成构造器中的代码执行初始化.如果一个类中有3个字段,3个构