目录
泛型
1.泛型(generic)
泛型的意义:委托可以让方法参数化,泛型可以让类型参数化。泛型代表的是通用类型,它可以代替任意的数据类型,使类型参数化,从而达到只实现一个方法就可以操作多种数据类型的目的。
使用泛型的好处:泛型可以避免不同类型转换时带来的数据损失,提供了更好的性能和类型安全特性。
泛型的定义:泛型将方法实现行为与方法操作的数据类型分离,实现代码重用。
用.NET类库声明并初始化泛型的语法: List<T> 变量名 = new List<T>();
泛型类声明并初始化的语法: class 类名1<T> where T:类名2{...}
泛型方法声明并初始化的语法: static T 方法名(T 形参, ...){...}
泛型语法解读:
- List<T> 是.NET类库中实现的泛型类型
- T是泛型参数(可以理解为形参)
- 类名<T>是泛型类
- where是类型参数的约束,它用来使类型参数可以适用于类型2中的方法。
泛型的示例:
class Program
{
static void Main(string[] args)
{
//用int作为实际参数来初始化泛型类型
List<int> intList=new List<int>();
//从int列表添加元素3
intList.Add(3);
//用string作为实际参数来初始化泛型类型
List<string> stringList=new List<string>();
//从string列表添加元素3
stringList.Add("3");
}
}
泛型的使用:用泛型来写比较两数大小的方法
//泛型类
public class Compare<T> where T:ICompare
{
//泛型方法
public static T compareGeneric(T a1,T a2)
{
if(a1.CompareTo(a2)>0)
{
return a1;
}
else
return a2;
}
}
public class Program
{
static void Main(string[] args)
{
//调用泛型方法
Console.WriteLine(Compare<int>.compareGeneric(1,3));
Console.WriteLine(Compare<string>.compareGeneric("a","as"));
}
}
2.泛型详解
2.1 类型参数T
类型参数T的定义:类型参数T是泛型参数(可以理解为形参)。它是一个可被数据类型替代的参数,当我们调用泛型时,我们需要初始化T,替代T的数据类型(如int、string等)可以被看做实参。
使用类型参数T时的两种情况:
- 泛型分为两类:未绑定的泛型、已构造的泛型
- 未绑定的泛型:没有T被替代
- 已构造的泛型:有T被替代
- 已构造的泛型分为两种:开放类型、封闭类型
- 开放类型:有T被替代,但未全被替代。
- 封闭类型:T全被替代。
注意:当你用 数据类型1 替代 类型参数T 后,泛型数组中的列表不能容纳 数据类型1 以外的数据类型变量。
2.2 泛型中的静态字段和静态函数问题
问:静态数据类型是属于类型的。对于静态数据而言,一个类只有一份。对于泛型类型,静态类也只有一份吗?
答:不,每个封闭的泛型类型都有仅属于自己的静态数据。
2.3类型参数的约束(where关键字)
类型参数约束的意义:当我们需要在泛型类中从别的类调用方法的时候,我们的类型参数T未为任意类型,而有的类型并没有提供想要调用的方法,此时编译器会报错。而where的存在可以把T类型的范围控制在可以调用方法的类型中。
where关键字的作用:限制某个类型实参的类型。
C#的四种约束:引用类型约束、值类型约束、构造函数类型约束、转换类型约束。
2.3.1 引用类型约束
引用类型约束的语法: T:class
引用类型约束的作用:它确保传递的类型实参必须是引用类型。
2.3.2 值类型约束
值类型约束的语法: T:struct
值类型约束的作用:它确保传递的类型实参必须是值类型。(包括枚举,不包括可空类型 )
2.3.3 构造函数类型约束
构造函数类型约束的语法: T:new()
构造函数类型约束的作用:它确保传递的类型实参必须是构造函数类型。
使用构造函数类型约束的要求:
- 若有多个约束,则此约束必须放在最后。
2.3.4 转换类型约束
转换类型约束的语法: T:基类名、T:接口名、T:U
转换类型约束语法解读:
- T:基类名:确保传递的类型实参必须是基类或其基类的派生类
- T:接口名:确保指定的类型实参必须是接口或实现了该接口的类
- T:U :确保指定的类型实参必须是U提供的类型实参或派生于U提供的类型实参
示例: