CLR via C#(16)--泛型

时间:2022-08-27 09:41:49

泛型就像是一个模板,常常定义一些通用的算法,具体调用时再替换成实际的数据类型,提高了代码的可重用性。


一、初识泛型

1. 简单实例

以最常用的FCL中的泛型List<T >为例:

static void Main(string[] args)
       {
           List<int> num = new List<int>();
           num.Add(1);
           num.Add(3);
           int num1 = num[0];
           int num2 = num[1];
       }

CLR via C#(16)--泛型

尖括号中的T是不确定的数据类型,叫做类型参数,一般规定以字母T开头,可以是TKey, TValue都可以。而调用时指定的具体类型叫做类型实参。

查看一下IL代码:

CLR via C#(16)--泛型

  • 类型名List是以“`”加数字结尾的。数字表示类型的元数,也就是需要指定具体类型的参数个数。
  • 泛型是类型安全的。如果用“num.Add("a");”会发生编译错误;
  • 泛型可以提高算法的可重用性,而且从例子中看出int类型并没有进行装箱拆箱操作,相比将所有类型转换为Object的方式而言,提高了程序的性能。
  • 为泛型变量设置默认值时常使用default关键字进行,T temp=default(T)。如果T为引用类型,则temp为null;如果T为值类型,则temp设为0值.
2. 开放类型与封闭类型:

开放类型:具有泛型参数的类型是开放类型,如List<T>,CLR不允许构造开放类型的实例;

封闭类型:在实际调用代码时,如果所有类型实参都已经指定了实际数据类型,如List<string>,则该类型为封闭类型。CLR允许构造封闭类型的实例。

3. 类型推断:

先看这段很常见的代码:

CLR via C#(16)--泛型

为了增强可读性,编译器支持类型推断功能,省略<>,我们可以将上面调用的方法改为:

CLR via C#(16)--泛型

* 需要注意的是,类型推断时C#使用的是变量的数据类型,而不是变量引用的对象的类型。例如:

CLR via C#(16)--泛型

虽然s1和s2都是指向了字符串对象,但是这两个变量的类型是不同的,所以会产生编译错误。

二、协变和逆变泛型类型参数

通过协变量和逆变量,可以将泛型委托或者接口的类型参数进行一定的类型转换。

  • 逆变量:泛型类型参数可以从基类转为派生类,用in关键字标识,只出现在输入位置,例如方法的参数;

public delegate void Func<in T>(T arg);

static void Main(string[] args)

{

Func<object> f1 = null;

Func<string> f2 = f1;

}

  • 协变量:泛型类型参数可以从派生类改为它的基类,用out关键字标识,只出现在输出位置,例如方法的返回值。

public delegate TResult Func<out TResult>();

static void Main(string[] args)

{

Func<string> fn=null;

object result=fn();

}

三、泛型约束

在设计泛型的类型参数时,可以通过where子句指定类型需要满足的约束条件。主要包含以下几种约束方式:

1. 主要约束

一个类型参数可以指定0或1个主要约束,主要约束可以一个非密封的引用类型,它表示类型实参必须与约束类型相同或者为约束类型的派生类。该引用类型不能为Object, Array, Delegate, MulticastDelegate, ValueType, Enum, Void。

class Constraint1<T> where T : Stream
{
     public void Close(T stream)
     {
         stream.Close();
     }
}

class Program
{
     static void Main(string[] args)
     {
         Constraint1<FileStream> s2 = new Constraint1<FileStream>();
     }
}

两种特殊的主要约束:class和struct。

  • Class约束:要求指定的类型实参必须是引用类型。Where T:class

CLR via C#(16)--泛型

在没有约束的情况下,如果T为值类型,是不能赋值为null的,所以会产生编译错误。添加约束后编译通过:

CLR via C#(16)--泛型

  • Struct 约束:要求指定的类型实参必须是值类型

CLR via C#(16)--泛型

在没有约束的情况下,如果T为引用类型是不能声明为可空值类型的,所以会产生编译错误。添加struct约束后运行正常:

CLR via C#(16)--泛型

2. 次要约束

一个类型参数可以指定0或者多个次要约束。常见的次要约束主要有两种:

  • 接口约束:类型实参必须实现了指定的所有接口。例如:

CLR via C#(16)--泛型

接口约束的另外一个好处是:值类型实参调用接口方法时不用进行装箱操作。

  • 类型参数约束:在指定的类型实参之间,存在着一定关系。例如要求存在继承关系:

CLR via C#(16)--泛型

3. 构造器约束

构造器约束要求类型实参必须实现了无参构造器,而且它不支持有参构造器。

CLR via C#(16)--泛型

CLR via C#(16)--泛型的更多相关文章

  1. 【Clr in c&num;】泛型

    使用泛型的好处是“代码重用”,极大的提高了开发效率,泛型为开发者提供了以下优势: 1,源代码保护  算法的源代码不需要提供给使用泛型算法的开发人员,使用c++模板的泛型技术需要提供.(目前c++模板的 ...

  2. &lbrack;CLR via C&num;&rsqb;16&period; 数组

    数组是允许将多个数据项当作一个集合来处理的机制.CLR支持一维数组.多维数组和交错数据(即由数组构成的数组).所有数组类型都隐式地从System.Array抽象类派生,后者又派生自System.Obj ...

  3. &lbrack;CLR via C&num;&rsqb;12&period; 泛型

    泛型(generic)是CLR和编程语言提供一种特殊机制,它支持另一种形式的代码重用,即"算法重用". 简单地说,开发人员先定义好一个算法,比如排序.搜索.交换等.但是定义算法的开 ...

  4. CLR类型设计之泛型(二)

    在上一篇文章中,介绍了什么是泛型,以及泛型和非泛型的区别,这篇文章主要讲一些泛型的高级用法,泛型方法,泛型接口和泛型委托,协变和逆变泛型类型参数和约束性,泛型的高级用法在平时的业务中用的不多,多用于封 ...

  5. CLR类型设计之泛型(一)

    在讨论泛型之前,我们先讨论一下在没有泛型的世界里,如果我们想要创建一个独立于被包含类型的类和方法,我们需要定义objece类型,但是使用object就要面对装箱和拆箱的操作,装箱和拆箱会很损耗性能,我 ...

  6. CLR via C&num;关于泛型(Generics )的摘录

    泛型,是CLR和编程语言提供的一种特殊机制,它支持另一种形式的代码重用,即“算法重用”. 简单的说,开发人员先定义好一个算法,比如排序.搜索.交换.比较或者转换等.但是,定义算法的开发人员并不设改算法 ...

  7. 重温CLR(八 ) 泛型

    熟悉面向对象编程的开发人员都深谙面向对象的好处,其中一个好处是代码重用,它极大提高了开发效率.也就是说,可以派生出一个类,让他继承基类的所有能力.派生类只需要重写虚方法,或添加一些新方法,就可定制派生 ...

  8. 读&lt&semi;&lt&semi;CLR via C&num;&gt&semi;&gt&semi; 详谈泛型

    1,什么是泛型? 答:泛型是类型的模板,类型是实例(对象)的模板.C#提供了5种泛型:类,接口,委托,结构和方法. 2,使用泛型有什么好处? 答:继承实现的是"代码重用",而泛型实 ...

  9. 《CLR via C&num;》读书笔记 之 泛型

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

随机推荐

  1. 购物车相关 js

    <div class="caigou"> <form action="" method="post"> <di ...

  2. java基础1&lowbar;标识符,数据类型

    JDK的卸载与安装 : 1  卸载 a 从程序中卸载   控制面板 - 程序和功能 - 卸载JDK; b 删除  C:\Windows\System32 下面的  java   javac  java ...

  3. AP&lpar;affinity propagation)研究

    待补充…… AP算法,即Affinity propagation,是Brendan J. Frey* 和Delbert Dueck于2007年在science上提出的一种算法(文章链接,*) 现 ...

  4. POJ 1015 Jury Compromise 2个月后重做,其实这是背包题目

    http://poj.org/problem?id=1015 题目大意:在遥远的国家佛罗布尼亚,嫌犯是否有罪,须由陪审团决定.陪审团是由法官从公众中挑选的.先随机挑选n个人作为陪审团的候选人,然后再从 ...

  5. spring中的bean

    环境准备 Eclipse上新建一个简单的maven工程,Artifact Id选择maven-archetype-quickstart: 添加spring-context依赖: <depende ...

  6. NotePad&plus;&plus; 列模式(在多行开头统一添加相同内容)

    ==> 按住Alt键不放,用鼠标左键从第一行的开头处按住向下拉,直到所有行 松开Alt键和鼠标左键,你会发现光标变成了一条跨越所有行的竖线 ==> 如果不想使用鼠标操作,可以使用 Alt+ ...

  7. Spring MVC 与 web开发

    转载:http://coderbee.net/index.php/java/20140719/959 项目组用了 Spring MVC 进行开发,觉得对里面的使用方式不是很满意,就想,如果是我来搭建开 ...

  8. xshell十大技巧

    xshell是我用过的最好用的ssh客户端工具,没有之一.这个软件完全免费,简单易用,可以满足通过ssh管理linux vps所有需要,唯一遗憾的是没有官方中文版. 警告:不要下载所谓的汉化版,可能有 ...

  9. Qt编程可不可以结合其他的第三方库和本土API?(有zeroMQ的Qt封装,还可轻易使用Python的库)

    作者:渡世白玉链接:http://www.zhihu.com/question/29030777/answer/59378712来源:知乎著作权归作者所有,转载请联系作者获得授权. 可以,十分可以,你 ...

  10. Unreal Engine 4 C&plus;&plus; 能够创建角色Zoom摄像头&lpar;资源&rpar;

    游戏摄像头可以观察到的距离越近,作用和拉远是一个比较普遍的要求,UE4它也实现比较简单. 在这篇文章中TopDown模板案例,解释如何,分步实施能Zoom摄像头. 创建TopDown模板C++项目达产 ...