一、泛型介绍
泛型类和泛型方法兼具可重用性、类型安全性和效率,这是非泛型类和非泛型方法无法实现的。 泛型通常与集合以及作用于集合的方法一起使用。 .NET Framework 2.0 版类库提供新的命名空间 System.Collections.Generic,其中包含几个新的基于泛型的集合类。
二、泛型的演变史
新建一个类为CommonMethod,将使用C#1.0的普通方法、object进行相比较,如图:

2.使用object传值
将传入值为object类型

在上面叙述的,普通方法和object类型传值相比较的话object传值比普通方法重用性高。 1.为什么object可以传输任何值? 原因:object是一切类型的父类。
2.为什么是父类就可以传输任何值? 原因:因为面向对象语言的3大特性:封装,继承,多态 继承的定义:如何任何父类出现的地方,都可以用子类来替换
3.普及一下隐式替换原则? 隐式替换原则:任何父类出现的地方,都可以用子类来替换,而且不会产生任何变化
但是使用object也有问题: 性能:当传入值类型的时候,会出现装箱拆箱,影响性能 因为这样object会很影响性能,所以在C#2.0的时候出来的泛型
三、如何声明和使用泛型
泛型是C#2.0的时候推出,泛型的作用:用来代码的重用

1.泛型的声明:在方法名后面加一个<名称>(名称可以是随意的英文字,但是不能使用关键字),泛型的T为类型的参数
2.泛型的传入:类型参数和参数必须匹配
3.泛型的特点:类型参数可以省略,由编译器推断出来
4.泛型的好处:更安全并且速度更快,特别适用于列表项的值类型的情况
5.测试泛型、object和普通方法的性能:普通方法=泛型方法<object方法
四、泛型类、泛型方法、泛型接口、泛型委托

1.泛型本质:满足任何不同类型
2.泛型可以做参数也可以坐返回值
3.泛型类内可以嵌套泛型方法
4.普通类要继承泛型类须指定泛型参数,或者将普通类也变成泛型类(泛型接口和泛型委托都是一样的)
泛型类
1.定义:泛型类封装不特定于特定数据类型的操作。泛型类最常见用法是用于链表列表、哈希表、堆栈、队列和树等集合。
2.重要注意事项:
(1)要将那些类型泛化为类型参数:通常,可参数化的类型越多,代码就越灵活、其可重用性就越高,但过度泛化会造成其他开发人员难以阅读或理解代码,
(2)要将何种约束(如有)应用到类型参数:其中一个有用的规则是,应用最大程度的约束,同时仍可处理必须处理的类型。 例如,如果知道泛型类仅用于引用类型,则请应用类约束。 这可防止将类意外用于值类型,并使你可在 T 上使用 as 运算符和检查 null 值 (3)是否将泛型行为分解为基类和子类:因为泛型类可用作基类,所以非泛型类的相同设计注意事项在此也适合
(4)实现一个泛型接口还是多个泛型接口:例如,如果要设计用于在基于泛型的集合中创建项的类,则可能必须实现一个接口,例如 IComparable<T>,其中 T 为类的类型。
3.类型参数约束的规则对于泛型类行为具有多种含义,尤其是在继承性和成员可访问性方面。对于泛型类Node<T>,客户端代码可以通过指定类型参数来引用类,创建封闭式构造类型Node<int>。
4.非泛型类(即,具体类)可继承自封闭式构造基类,但不可继承自开放式构造类或类型参数,因为运行时客户端代码无法实例化基类所需的类型参数
5.继承自开放式构造类型的泛型类必须对非此继承类共享的任何基类类型参数提供类型参数
6.继承自开放式构造类型是泛型类必须指定作为基类型上约束超集或表示这些约束的约束
7.泛型类型可以使用多个类型参数和约束
8.开放式构造和封闭式构造类型可用作方法参数
9.如果一个泛型类实现一个接口,则该类的所有实例均可强制转换为该接口
泛型接口
1.为泛型集合类或表示集合中的项的泛型类定义接口通常很有用处。为避免对值类型的装箱和取消装箱操作,泛型类的首选项只用泛型接口。
2..net framework类库定义多个泛型接口,已将其用于System.Collections.Generic 命名空间的集合类
3.接口被指定为类型参数上的约束时,仅可使用实现接口的类型。
4.可将多个接口指定为单个类型上的约束,一个接口可定义多个类型参数,适用于类的继承规则也适合于接口
泛型方法
1.泛型方法是通过类型参数声明,还可省略类型参数,编译器将推断类型参数
2.推断类型参数的原理:相同规则使用于静态方法和实例方法。编译器可基于传入的方法参数推断类型参数;而无法仅根据约束或返回值推断类型参数,因此,类型推断不适用于不具有参数的方法
3.如果定义一个具有与包含类相同的类型参数的泛型方法,则编译器会生成警告CS0693,因为在该方法范围内,向内T提供的参数会隐藏向外T提供的参数。
泛型委托
1.委托可以定义它自己的类型参数。引用泛型委托的代码可以指定类型参数以创建封闭式构造类型,就像实例化泛型类或调用泛型方法一样
2.在泛型类中定义的委托可以用类方法使用的相同方式来使用泛型类类型参数
3.引用泛型的代码必须指定包含类的类型参数
4.根据典型设计模式定义事件时,泛型委托特别有用,因为发件人参数可以为强类型,无需在它和 Object 之间强制转换。
五、泛型约束
1.定义:泛型约束等于指定一个类型
2.约束后,只能看约束传递
3.泛型约束的作用:
(1)在泛型方法内可以直接使用基类的属性和方法
(2)在调用的时候只能传递基类或者基类的子类
4.六种类型的约束
(1)T:结构:类型参数是值类型,可以指定除Nullable以外的任何值类型。
(2)T:类型:类型参数必须是引用类型,包括任何类、接口、委托或数组类型。
(3)T:new():类型参数必须具有无参数的公共结构函数。当与其他约束一起使用时,new()约束必须为最后指定
(4)T:<基类名>:类型参数必须是指定的基类或者派生自指定的基类
(5)T:<接口名称>:类型参数必须是指定的接口。可以指定多个接口结束。约束接口也可以是泛型
(6)T:U:为T提供的类型参数必须是为U提供的参数或派生自为U提供的参数。这称为裸类型约束
5.在应用where T:class约束是,不建议使用参数使用==和!=运算符, 因为这些运算符仅测试引用同一性而不测试值相等性
6.未绑定的类型参数(没有约束的类型参数)
(1)不能使用!=和==运算符,因为无法保证具体类型参数能支持这些运算符
(2)可以在他们与System。Object之间来回转换,或将它们显示转换为任何接口类型
(3)可以将它们与null进行比较。将未绑定的参数与null进行比较时,如果类型参数为值类型,则该比较将始终返回false
7.裸类型约束
(1)定义:作为约束的泛型类型称为裸类型约束
(2)用途:
(a)当具有自己的类型参数的成员函数需要将该参数约束为包含类型的类型参数时,裸类型很有用
(b)裸类型约束还可以在泛型类定义中使用(注意:还必须已经和其他任何类型参数一起在尖括号中声明了裸类型约束)
(3)局限:泛型类的裸类型约束的作用非常有限,因为编译器处理假设某个裸类型约束派生自System.Object以外,不会做其他任何假设
泛型约束的图片


六、协变、逆变
1.out 协变 covariant 修饰返回值 IEnumerable
(1) IEnumerable是一个迭代器,只能修饰返回值
(2) 定义:泛型参数前面加了一个out,他就叫做协变,协变的效果就是在实例化时可以是当前的类和类的子类
2.in 逆变 contravariant 修饰传入参数
(1) 定义:泛型参数前面加一个in, 他就叫做逆变,ICustomerListIn
(2) 用法:in 逆变 只能是传入值(传入值),不能作为返回参数
协变

逆变

七、泛型和反射
1.因为公共语言运行时(CLR)能够在运行时访问泛型类型信息,所以可以使用反射获取关于泛型类型的信息,方法与用于非泛型类型的方法相同
2.有关泛型反射中使用的术语的固定条件列表(System.Type 成员名称)
(1)IsGenericType:如果类型是泛型,则返回True
(2)GetGenericArguments:返回Type对象的数组,这些对象表示为构造类型提供的类型实参或泛型类型型定义的类型参数
(3)GetGenericTypeDefinition:返回当前构造类型的基础泛型类型定义
(4)GetGenericParameterConstraints:返回表示当前泛型类型参数约束的Type对象的数组
(5)ContainsGenericParameters:如果类型或任何其封闭类型或方法包含未提供特定类型的类型参数,则返回true
(6)GenericParameterAttributes:获取描述当前泛型类型参数的特殊约束的GenericParameterAttributes标志组合
(7)GenericParameterPosition:对于表示类型参数的Type对象,获取类型参数在声明其类型参数的泛型类型定义或泛型方法定义的泛型参数列表中的位置
(8)IsGenericParameter:获取一个值,该值指定当前Type是否表示泛型类型或方法定义中的类型参数
(9)IsGenericTypeDefinition:获取一个值,该值指示当前Type是否可以用来构造其他泛型类型或泛型类型定义。如果该类型表示泛型类型的定义,则返回true
(10)DeclaringMethod:返回定义当前泛型类型参数的泛型方法,如果类型参数未由泛型方法定义,则返回NUll
(11)MakeGenericType:替代有当前泛型类型定义的类型参数组成的类型数组的元素,并返回表示结果构造类型的Type对象
3.新成员将添加到MethodInfo类来启用泛型方法的运行是的信息。有关用于反射泛型方法的术语的固定条件列表,请参阅IsGenericMethod属性注解(System.Reflection.MemberInfo 成员名称):
(1)IsGenericMethod:如果方法是泛型,则返回True。
(2)GetGenericArguments:返回类型对象的数组,这些对象表示构造泛型方法的类型实参或泛型方法定义的类型参数
(3)GetGenericMethodDefinition:返回当前构造方法的基础泛型方法定义
(4)ContainsGenericParameters:如果方法或任何其封闭类型包含未提供特定类型的任何类型参数,则返回True。
(5)IsGenericMethodDefinition:如果当前MethodInfo表示泛型方法的定义,则返回True
(6)MakeGenericMethod:用类型数组的元素替代当前泛型方法定义的类型参数,并返回表示结果构造方法的MethodInfo对象。
八、泛型和特性
1.属性可按与非泛型类型相同的方法应用到泛型类型。
2.仅允许自定义属性引用开放式泛型类型(即未向其提供任何类型参数的泛型类型)和封闭式构造泛型类型(即向所有类型参数提供参数的泛型类型)
3.属性可引用开放式泛型类型
4.通过使用使用适当数量的逗号指定多个类型泛型。
5.属性可引用封闭式构造泛型类型
6.引用泛型类型参数的属性会导致编译时报错
7.不能从Attribute继承泛型类型
浙公网安备 33010602011771号