一、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第十六课:推荐系统(Recommender Systems)

    16.1  问题形式化 16.2  基于内容的推荐系统 16.3  协同过滤 16.4  协同过滤算法 16.5  矢量化:低秩矩阵分解 16.6  推行工作上的细节:均值归一化 16.1  问题形式 ...

  2. 属性动画和Activity、Fragment过渡动画等

    主题是关于动画的,但是不是什么动画的内容都包括.先泛泛的介绍一下,然后详细的介绍一下翻代码找见的一个好玩的动画的使用.以下的内容包括Android 3和Android 3.1等引入的API,在使用中请 ...

  3. Swift: 用UserDefaults保存复杂对象

    一直木有看过这个细节,用UserDefaults是能不能存复杂一点的对象.大家可能都看到过UserDefaults的一个方法setObject: forKey:,用这个方法存过NSDictionary ...

  4. POJ3181--Dollar Dayz(动态规划)

    Farmer John goes to Dollar Days at The Cow Store and discovers an unlimited number of tools on sale. ...

  5. Q他中的乱码再理解

    Qt版本有用4的版本的也有用5的版本,并且还有windows与linux跨平台的需求. 经常出现个问题是windows的解决了,源代码放到linux上编译不通过或者中文会乱码,本文主要是得出一个解决方 ...

  6. spark 中划分stage的思路

    窄依赖指父RDD的每一个分区最多被一个子RDD的分区所用,表现为 一个父RDD的分区对应于一个子RDD的分区 两个父RDD的分区对应于一个子RDD 的分区. 宽依赖指子RDD的每个分区都要依赖于父RD ...

  7. NoSQL数据库的分布式算法

    本文译自 Distributed Algorithms in NoSQL Databases 系统的可扩展性是推动NoSQL运动发展的的主要理由,包含了分布式系统协调,故障转移,资源管理和许多其他特性 ...

  8. Spring中注入bean学习的总结

    1.在类上直接加注解@Component,那么这个类就直接注入到Spring容器中了  ,像@Contrloller,@Service这些本质上都是@Component, 2.@Configurati ...

  9. hdu 1.2.6

    勾股定理... #include<cstdio> #include<algorithm> using namespace std; int main() { //freopen ...

  10. linux常用命令(二)文件上传下载及软件安装

    1.上传下载工具安装 (1)WINDOWS 到linux的文件上传及下载: windows下打开secureCRT,通过SSH连到⾄至远程linux主机:上传下载工具安装命令:yum -y insta ...