一、C#中的泛型引入了类型参数的概念,类似于C++中的模板,类型参数可以使类型或方法中的一个或多个类型的指定推迟到实例化或调用时,使用泛型可以更大程度的重用代码、保护类型安全性并提高性能;可以创建自定义的泛型类型(类、结构、接口、委托)和泛型方法;

  1.在泛型类型的定义或泛型方法的声明中,类型参数是类型的占位符,这些占位符指代的类型需要在实例化泛型类型或调用泛型方法时进行指定;

  ※类型参数一般以T命名,如果是多个,使用T、U、V等,如果有指定约束,可以结合约束命名,例如需要继承自MyClass的类型参数命名为TMyClass;任何命名都并不会给类型参数增加额外作用;

  2.泛型是运行时起作用的一套机制,根据运行时类型参数被指定为值类型还是引用类型其使用方式有所不同:

  ※当类型参数被指定为值类型时,会在第一次指定该特定值类型的类型时创建该类型唯一的专用化泛型类型,泛型类型中的类型参数会被替换为相应的值类型;

  ※当类型参数被指定为引用类型时,会在第一次指定任意引用类型时创建一个通用化泛型类型,泛型类型中的类型参数会被替换为该引用类型,并在之后每次指定为引用类型时重用该泛型类型并修改其中类型参数的类型;造成这种差异的原因可能在于所有的引用大小相同;

  二、这篇我们先了解下泛型类,泛型类的定义中可以将类型参数用作成员变量的类型或方法中参数列表、返回值的类型:

class MyClass<T> //声明具有一个类型参数的泛型类,可以有多个类型参数,用,隔开:<T, U>
{
public T MyObj; //声明T类型的字段
private Type myGenericField = typeof(T); //在泛型类内部可以获取类型参数的类型信息
//do…
}
//声明泛型类的实例,指定类型参数为int类型
MyClass<int> myObj = new MyClass<int>();

  1.在定义泛型类型时,可以对类型参数的种类添加限制,这些限制称为约束(Constraint),使用约束可以增加类型参数所能进行操作和调用方法的数量;约束使用上下文关键字where指定,位于基类和接口之后,例如:

class MyClass<T> : MyBaseClass where T : MyType //指定基类约束,T需要是指定的类MyType或继承自类MyType,基类约束需要在所有约束之前,基类约束本身也可以是泛型类型,例如MyType<T>

  ※其它特殊的约束:

  where T : IMyInterface //指定接口约束,T需要是指定的接口IMyInterface或实现接口IMyInterface,可以同时指定多个接口约束,接口约束本身也可以是泛型类型,例如IMyInterface<T>
  where T : class //指定类型约束,T需要是类类型
  where T : struct //指定类型约束,T需要是值类型,但不可以是可空类型
  where T : new() //类型参数必须有公共的无参数构造函数,与其他约束一起使用时,new()约束必须最后指定;由于结构的定义中一定包含无参数构造函数,所以struct约束包含new()约束,二者不可同时使用,通常与class约束一起使用:class, new()
  where T : struct where U : class //给多个类型参数指定约束
  where U : T //类型参数作为约束,类型参数U继承自类型参数T

  ※可以对一个类型参数应用多个约束,多个约束使用,隔开:where T : MyType, IMyInterface;

  ※没有约束的类型参数称为未绑定类型参数(Unbounded Type Parameter),这些类型参数的变量在使用时不可以使用==和!=运算符,因为无法保证运行时指定的类型支持这些运算符;

  ※对于使用类型约束class的类型参数,应避免对其变量使用==和!=运算符,因为在泛型中这些运算符仅会根据引用来判断是否相等,即使类型对==和!=运算符进行了重载也不行;如果必须根据值进行判断,应给类型参数加入基类约束IEquatable<T>或IComparable<T>并在类型中实现它们,比较时使用Equals或CompareTo;

  ※从C#7.3开始,可以使用特殊类型System.Delegate、System.MulticastDelegate和System.Enum作为基类约束中的基类,还可以使用非托管类型unmanaged作为类型约束中的类型;

  2.非泛型类(即具体类,Concrete Class)只可以继承自具体类或封闭式构造类(即指定了所有类型参数的泛型类,Closed Constructed Class),不可以继承自开放式构造类(即没有完全指定所有类型参数的泛型类,Open Constructed Class);泛型类可以继承自具体类和封闭式构造类,也可以继承自开放式构造类,继承自开放式构造类时,派生类的类型参数中必须包含基类中未指定类型的类型参数,同时,派生类中这些类型参数的约束必须为基类中对应类型参数约束的超集;可以总结为以下几种情况:

//对于基类为具体类或仅有一个类型参数的情况
class BaseClass { }
class BaseGenericClass<T> { }
//定义一个泛型类,继承具体类BaseClass
class MyClass<T> : BaseClass { }
//定义一个泛型类,继承自指封闭式构造类BaseGenericClass<int>
class MyClass<T> : BaseGenericClass<int> { }
//定义一个泛型类,继承自开放式构造类BaseGenericClass<T>
class MyClass<T> : BaseGenericClass<T> { }
//定义一个非泛型类,继承自封闭式构造类BaseGenericClass<int>
class MyClass : BaseGenericClass<int> { }
//对于基类有多个类型参数的情况
class MultipleBaseGenericClass<T, U> { }
//定义一个泛型类,继承自开放式构造类MultipleBaseGenericClass<T, int>
class MyClass<T> : MultipleBaseGenericClass<T, int> { }
//定义一个泛型类,继承自开放式构造类MultipleBaseGenericClass<T, U>
class MyClass<T, U> : MultipleBaseGenericClass<T, U> { }
//定义一个非泛型类,继承自封闭式构造类MultipleBaseGenericClass<int, string>
class MyClass : MultipleBaseGenericClass<int, string> { }

  ※在继承中,派生类类型的对象可以通过隐式转换赋值给基类类型的变量,这同样适用于泛型类型的对象,例如泛型类List<T>继承自泛型接口IList<T>,那么可以把List<int>类型的对象隐式转换为IList<int>类型的变量:

IList<int> iList = new List<int>();

  3.泛型类为不可变量,泛型类型相同但类型参数指定类型不同的泛型类型即是不同的类型,它们之间不能进行类型转换(即使类型参数指定的类型之间存在类型转换关系),例如不能把List<DerivedClass>类型的对象赋值给一个List<BaseClass>类型的变量;

  4.泛型类最常见的用途是创建泛型集合类,在命名空间System.Collections.Generic中包含系统定义的各种泛型集合类,应尽可能的使用这些泛型集合来代替普通的集合;


如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的认可是我写作的最大动力!

作者:Minotauros
出处:https://www.cnblogs.com/minotauros/

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

详解C#泛型(一)的更多相关文章

  1. 详解C#泛型(三)

    一.前面两篇文章分别介绍了定义泛型类型.泛型委托.泛型接口以及声明泛型方法: 详解C#泛型(一) 详解C#泛型(二) 首先回顾下如何构建泛型类: public class MyClass<T&g ...

  2. 详解C#泛型(二) 获取C#中方法的执行时间及其代码注入 详解C#泛型(一) 详解C#委托和事件(二) 详解C#特性和反射(四) 记一次.net core调用SOAP接口遇到的问题 C# WebRequest.Create 锚点“#”字符问题 根据内容来产生一个二维码

    详解C#泛型(二)   一.自定义泛型方法(Generic Method),将类型参数用作参数列表或返回值的类型: void MyFunc<T>() //声明具有一个类型参数的泛型方法 { ...

  3. 详解C#泛型(二)

    一.自定义泛型方法(Generic Method),将类型参数用作参数列表或返回值的类型: void MyFunc<T>() //声明具有一个类型参数的泛型方法 { Type generi ...

  4. 一文详解scala泛型及类型限定

    今天知识星球球友,微信问浪尖了一个spark源码阅读中的类型限定问题.这个在spark源码很多处出现,所以今天浪尖就整理一下scala类型限定的内容.希望对大家有帮助. scala类型参数要点 1. ...

  5. Java泛型详解(转)

    文章转自  importNew:Java 泛型详解 引言 泛型是Java中一个非常重要的知识点,在Java集合类框架中泛型被广泛应用.本文我们将从零开始来看一下Java泛型的设计,将会涉及到通配符处理 ...

  6. java 泛型详解(普通泛型、 通配符、 泛型接口)

    java 泛型详解(普通泛型. 通配符. 泛型接口) JDK1.5 令我们期待很久,可是当他发布的时候却更换版本号为5.0.这说明Java已经有大幅度的变化.本文将讲解JDK5.0支持的新功能---- ...

  7. java基础(十二 )-----Java泛型详解

    本文对java的泛型的概念和使用做了详尽的介绍. 概述 泛型在java中有很重要的地位,在面向对象编程及各种设计模式中有非常广泛的应用. 什么是泛型?为什么要使用泛型? 泛型,即“参数化类型”.一提到 ...

  8. Java基础11:Java泛型详解

    本文对java的泛型的概念和使用做了详尽的介绍. 本文参考https://blog.csdn.net/s10461/article/details/53941091 具体代码在我的GitHub中可以找 ...

  9. java 泛型详解-绝对是对泛型方法讲解最详细的,没有之一

    对java的泛型特性的了解仅限于表面的浅浅一层,直到在学习设计模式时发现有不了解的用法,才想起详细的记录一下. 本文参考java 泛型详解.Java中的泛型方法. java泛型详解 1. 概述 泛型在 ...

随机推荐

  1. Ng第十一课:机器学习系统的设计(Machine Learning System Design)

    11.1  首先要做什么 11.2  误差分析 11.3  类偏斜的误差度量 11.4  查全率和查准率之间的权衡 11.5  机器学习的数据 11.1  首先要做什么 在接下来的视频将谈到机器学习系 ...

  2. MapGIS10.3新功能

    智能的GIS 支持开放的数据集.数据库.等等 T-C-V 软件结构是继局部网软件的 C/S 结构,互联网软件的 B/S 结构发展起来的适合云 计算.云服务的新一代软件三层结构,分别为终端应用层(T 层 ...

  3. linux 常用命令(个人记录)

    Linux专家的秘诀:思考-实践-在思考-再实践...linux常用命令:root 管理员用户startx 进入shutdown -h now 立刻关机shutdown -r now 现在重新启动计算 ...

  4. spring父子Ioc容器的关系

    在网上找了一下,没有直接解说ioc父子容器关系的文章,所以大概看了下代码,自己写下吧,写俩行做个笔记. 1. 在进行dean的注册的时候,父容器和子容器是互不干扰的,各自注册自己的 2. 在实例化的时 ...

  5. 《mysql必知必会》学习_第三章_20180724_欢

    P16: use crashcourse; #选择数据库#使用crashcouse这个数据库,因为我没有crashcourse这个数据库,所以用我的hh数据库代替. P17: show databas ...

  6. lca tarjin

    这个算法  我个人认为是  遍历每一个点把它当成一些询问的最近祖先 1 2 3 4 5 6 low是并差集,vis是是否访问过,访问过为true,没有为false: 假设询问是(4,4),(4,5), ...

  7. ACE Editor在线代码编辑器简介及使用引导

    转自博客:https://www.cnblogs.com/cz-xjw/p/6476179.html ACE 是一个开源的.独立的.基于浏览器的代码编辑器,可以嵌入到任何web页面或JavaScrip ...

  8. zoj2607

    题意:如左图,给定A,B,C,D的面积分别为大于等于a,b,c,d,求最小的面积 思路:因为a,b肯定有一个是满的(不然还可压缩到更小),同理,ac,bd,cd都只有一个是满的,所以有可能是对角满的, ...

  9. vnc搭建

    PS:偶以前基本不用Linux的远程图形桌面,前几天有开发的同事配置CentOS的vnc有问题,找我解决,就顺便记录总结一下,这个总结是比较完整的.下面的配置在CentOS5.x和6.x.SUSE企业 ...

  10. socket粗解

    百度定义:网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket. Socket通信流程: 网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一 ...