文章目录
一、泛型概念
C# 语言和公共语言运行时 (CLR) 在 2.0 版本中添加了泛型。泛型将类型参数的概念引入 .NET Framework,这样就可以设计具有相同特征的类和方法:在客户端代码声明并初始化这些类和方法之前,这些类和方法会延迟指定一个或多个类型(使用占位符~3:数字代表类型参数个数)
二、泛型的作用
使用泛型类型可以最大限度地重用代码、保护类型安全性以及提高性能。泛型最常见的用途是创建集合类 List< int>。
1.泛型分类:
泛型接口、泛型类
、泛型方法
、泛型事件和泛型委托
。
2.泛型的好处
(1)增加类型的安全性
(2)提高代码的重用
三、泛型的使用
(一)泛型类
1.创建泛型类
2.案例:
//泛型类
class MyList<T>
{
T[] stack; //声明数组
int size; //数组长度
int stacPoint; //当前位置指针(索引)
public MyList(int length)
{
this.size = length;
stack = new T[size];
stacPoint = -1;
}
// 入栈
public void Add(T item)
{
if (stacPoint>=size) //如果超过数组长度
{
Console.WriteLine("集合已满");
}
else
{
stacPoint++;
stack[stacPoint] = item;
}
}
// 出栈
public T Pop()
{
T data = stack[stacPoint];
stacPoint--;
return data;
}
}
// 主运行窗口
static void Main(string[] args)
{
//实例化泛型类
MyList<int> list = new MyList<int>(6);
//入栈
list.Add(1);
list.Add(2);
list.Add(3);
list.Add(4);
list.Add(5);
//出栈
Console.WriteLine(list.Pop()); // 5
Console.WriteLine(list.Pop()); // 4
Console.WriteLine(list.Pop()); // 3
Console.WriteLine(list.Pop());// 2
Console.WriteLine(list.Pop());// 1
Console.ReadLine();
}
3.泛型类的规范:
public class 类名<T> {类成员....}
(1) T:仅代表一个占位符
,用T或者其他字母都行,只要符合C#命名规范都行,但是一般情况用T
(2) T:表示一个通用的数据类型,在使用的时候用实际类型代替
(3)T:泛型类可以在定义中可以包含多个任意类型
参数,参数之间使用逗号隔开
如
public class 类名<T1,T2,T3,....>{...}
各种类型参数
都可以用作成员变量的类型
、属性
、方法
等成员的返回类型,以及方法的参数类型
以上泛型类的使用,增加了类型安全,实例化时int类型的约束下是不能添加string类型。无需拆箱操作
4.泛型类型的问题
无法为泛型类型赋值初始
因为泛型类型可以理解为泛指所有的数据类型,而所有的数据类型可分为:值类型和引用类型,而且不同的数据类型支持的默认值是不一样的。
注意:
(1) 不能随便假设泛型类型是某种类型,这种类型也许没有构造方法,也许是私有的
(2) 解决方案使用default关键字,如果defalut中指定的类型最终是引用类型则默认是null,如果是值类型那就给值类型对应的默认值,数值就是0.结构类型要根据具体的成员类型确定是0还是null
(二)泛型方法
案例
static void Main(string[] args)
{
Console.WriteLine(Add<int>(11,12));//23
Console.WriteLine(Add<double>(11.5,12.5));// 24
//Console.WriteLine(Add<char>('a','b'));//异常实参不为值类型
Console.ReadLine();
}
//泛型方法
static T Add<T>(T a,T b) where T : struct
{
dynamic a1 = a; // 设置动态类型 根据程序执行动态获取当前类型
dynamic b1 = b;
return a1 + b1;
}
四、泛型约束
1.泛型约束有哪些
- where T : struct 类型参数必须是值类型。
- where T : class 类型参数必须是引用类型。 此约束还应用于任何类、接口、委托或数组类型。
- where T : unmanaged 类型参数不能是引用类型,并且任何嵌套级别均不能包含任何引用类型成员。
- where T : new() 类型参数必须具有公共无参数构造函数。
- where T : <基类名> 类型参数必须是指定的基类或派生自指定的基类
- where T : <接口名称> 类型参数必须是指定的接口或实现指定的接口
- where T : U 为 T 提供的类型参数必须是为 U 提供的参数或派生自为 U 提供的参数。
2.案例
static void Main(string[] args)
{
MyGenericClass<int, Course, Teacher> myGener = new MyGenericClass<int, Course, Teacher>();
myGener.ProductList = new List<Course>()
{
new Course(){CourseName="ASP.NET",Period=6},
new Course{CourseName="WEB",Period=5}
};
Course c = myGener.GetClass(0);
Console.WriteLine($"{c.CourseName}课程的周期{c.Period}");
Console.ReadLine();
}
//泛型类
class MyGenericClass<T1, T2, T3>
where T1:struct //值类型
where T2:class //引用类型 (还包含:类,接口,委托,数组)
where T3:new () //无参数构造函数
{
public List<T2> ProductList { get; set; } //声明以T2集合为类型的属性
public T3 Teachers { get; set; } //声明以T3为类型的属性
//声明以T2 为返回类型、T1类型为参数,的方法
public T2 GetClass(T1 num)
{
dynamic a = num; //根据T1获取到a的数据类型
return ProductList[a]; //返回数组中a索引对应的数据
}
}
//参数类 T2:代表所学的科目类
class Course
{
/// <summary>
/// 课程名称
/// </summary>
public string CourseName { get; set; }
/// <summary>
/// 学习周期
/// </summary>
public int Period { get; set; }
}
//参数类 T3:代表老师
class Teacher
{
/// <summary>
/// 姓名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 授课数量
/// </summary>
public int Count { get; set; }
}