泛型(Generic)
泛型集合List<T>、Dictionary<k,v> 所在命名空间:System.Collections.Generic;
比较非泛型:ArryList,Hastable 所在命名空间:System.Collections
非泛型集合ArryList里面可以添加任意类型,添加方便的对于数据本身来讲,是非常不安全的。
因为我们开发中很多时候,这些是不可控的。其次,还存在拆装箱的问题。
装箱:将值类型的元素,放到集合中会被转换成object类型。这个过程就叫装箱。
拆箱:将一个集合中的元素取出来,但是这个元素本质是值类型,必须强制类型转换。
弊端:程序中如果有大量的数据进行拆箱装箱,会很影响程序的性能。
1、泛型出现-->泛型概念:泛型是一种程序特性,定义的时候,是对这个类型不作出明确的规定,
但是当使用的时候,必须明确规定,并且不能改变。
2、泛型出现的场合:泛型集合、泛型方法、泛型类、泛型委托...
//编写一个出入站的泛型类
public class MyStack<T>
{
//准备一个泛型数组
private T[] stack;
//泛型位置
private int stackPoint;
//泛型数组大小
private int size;
public MyStack(int size)
{
this.size = size;
this.stackPoint = -1;
stack = new T[size];
}
/// <summary>
/// 元素入栈
/// </summary>
/// <param name="item"></param>
public void Push(T item)
{
if (stackPoint > size)
{
Console.WriteLine("数组入栈已满");
}
else
{
stackPoint++;
this.stack[stackPoint] = item;
}
}
/// <summary>
/// 元素出栈
/// </summary>
/// <returns></returns>
public T Pop()
{
T data = this.stack[stackPoint];
stackPoint--;
return data;
}
}
动态类型
在使用泛型类型时,不明确成员类型,不能new或者赋值null(值类型),使用default关键字可以解决这一问题。在使用var推断对象类型时,推断的对象类型必须明确,不能为泛型。
class Generic<T1,T2>
{
private T1 data1;
private T2 data2;
public Generic()
{
//data1 = new T1(); 没有确定是引用类型,不能使用new
//data1 = null; 很多情况下,值类型是不能为null
data1 = default(T1);//使用default,如果是引用类型要则赋值null,如果是值类型就给值类型默认值
data2 = default(T2);
}
}
泛型方法中如果不明确参数或者返回值类型,编译时解析的话,会引起程序报错,使用dynamic运行时做解析 ,可以处理这一问题。
public T2 BuyCourse(T1 position)
{
// return this.ProductList[position]; //直接写是错误的
// var index = position; //因为我们不能特别明确的知道T1是什么类型,使用var的时候,后面的类型必须是明确的
dynamic index = position;//dynamic是在运行时解析对象类型,在编译阶段是不解析的。
return this.ProductList[index];
}
泛型约束
目的:就是对泛型类型做出数据类型的要求,或者其他的条件。
public class MyGenericCalss1<T1, T2, T3,T4>
where T1 : struct //解释:T1必须是值类型
where T2 : class //解释:T2必须是引用类型
where T3 : new() //解释:T3这个类型中,必须有一个无参数的构造方法,这个约束必须放到最后
where T4: Imeeting //解释:T4类型参数必须是指定的接口或实现指定的接口。可以指定多个接口约束。约束接口也可以是泛型的。
//其他的类型:基类型、接口类型...