一、泛型类
public class GenericStack<T>
{
private T[] stackArray;//泛型数组
private int currentPosition;//当前位置
private int count;//栈的数据容量
public GenericStack(int count)
{
this.count = count;
this.stackArray = new T[count];//初始化数组大小
this.currentPosition = 0;/当前位置从0开始
}
//入栈
public void Push(T item)
{
if(currentPosition >= count)
{
Console.WriteLine("当前栈空间已满!");
}
else
{
this.stackArray[currentPosition] = item;
currentPosition++;
}
}
//出栈
public T Pop()
{
T result = this.stackArray[currentPosition-1];
currentPosition--;
return result ;
}
}
//调用
static void Main(string[] args)
{
GenericStack<int> stack1 = new GenericStack<int>(5);
stack1.Push(1);
stack1.Push(2);
stack1.Push(3);
stack1.Push(4);
stack1.Push(5);
stack1.Pop();
stack1.Pop();
stack1.Pop();
stack1.Pop();
stack1.Pop();
}
- 泛型好处:增加类型安全,编码灵活性提高
- 常见泛型:泛型类 泛型方法
- 泛型类规范:
- public class 类型<T>{类的成员...}
- T仅为占位符,符合C#命名规则即可,表示一个通用的数据类型,在使用时用实际的类型替代
- 如果包含任意多个类型的参数,参数之间用逗号分隔,如GenericStack<T1,T2,T3>{...},所定义的各种类型参数,可以用做成员变量的类型,属性,方法等返回值类型及方法参数...
二、泛型约束
//default关键字使用
public class GenericClass1<T1,T2>
{
private T1 obj1;
public GenericClass1()
{
//泛型使用的两种错误
//obj1 = null;
//obj1 = new T1();//不能人为假定某种类型,因为这种类型也许没有构造方法,也许是私有的
//解决方法
obj1 = default(T1);
}
}
//添加约束类型的泛型类
public class GenericClass2<T1,T2,T3>
where T2:class//类型必须为引用类型
where T3:new()//在这个类中,类型必须有一个无参构造,且必须把这个约束放在最后
//其他类型-->基类类型 where T2:T1{} 表示T2必须与T1类型相同或继承自T1
{
//产品列表
public List<T2> ProductList{get;set;}
//发行者
public T3 Publisher{get;set;}
public GenericClass2()
{
ProductList = new List<T2>();
Publisher = new T3();
}
//购买第几个产品
public T2 BuyProduct(T1 num)
{
//return ProductList[num];//直接写有错误,T1不一定为int类型
dynamic index = num;//转化为动态类型
return ProductList[index];
}
}
//根据泛型类要求设计参数(实际开发时自行设计)
class Course
{
public string CourseName{get;set;}//课程名称
public int Period{get;set;}//课程学习周期
}
class Teacher
{
public Teacher(){}
public string Name{get;set;}
public int Count{get;set;}//授课数量
}
static void Main(string[] args)
{
GenericClass2<int,Course,Teacher> myclass2 = new GenericClass2<int,Course,Teacher>();
myclass2.Publisher = new Teacher{Name = "",Count = 20};
myclass2.ProductList = new List<Course>()
{
new Course(){CourseName = "",Period = 6},
new Course(){CourseName = "",Period = 7}
}
Course myCourse = myclass2.BuyProduct(0);
Console.WriteLine("输出======");
}
三、泛型方法
//实现四则运算
static T Add1<T>(T a,T b)
{
return a + b;//写法错误
dynamic a1 = a;//动态类型仅在编译期间存在,运行期间会被object类型替代(编译时不考虑具体类型)
dynamic b1 = b;
return a1+b1;
}
static T Add2<T>(T a,T b)where T:struct
{
dynamic a1 = a;
dynamic b1 = b;
return a1+b1;
}
static T Sub<T>(T a,T b)where T:struct
{
dynamic a1 = a;
dynamic b1 = b;
return a1-b1;
}
static T Multiply<T>(T a,T b)where T:struct
{
dynamic a1 = a;
dynamic b1 = b;
return a1*b1;
}
static T Div<T>(T a,T b)where T:struct
{
dynamic a1 = a;
dynamic b1 = b;
return a1/b1;
}
//调用
static void Main(string[] args)
{
Add1(20,30);
Add2(10,20);
Sub(20.5,56);
Add2(20.5,5);
}
//实现一个数的求和
private static T Sum<T>(T a)where T : struct
{
int sum = default(T);
for(dynamic i=0;i<=a;i++)
{
sum+=i;
}
return sum;
}
四、泛型委托
static void Main(string[] args)
{
MyDeletegate<int> myDeletegate1 = Add;
MyDeletegate<double> myDeletegate2 = Sub;
//调用
myDeletegate1(10,20);
myDeletegate2(10.5,20.7);
}
//定义泛型委托
public deletegate T MyDeletegate(T a,T b);
static int Add(int a,int b)
{
return a+b;
}
static int Sub(double a,double b)
{
return a-b;
}
五、Action与Func
系统提供了没有返回值和一个返回值的泛型委托
//最多可以有16个参数
public Action<int,int,int> myAction = (a1,a2,a3)=>
{
int resule = (a1+a2)*a3
Console.WriteLine(result);
}
///最后一个表示返回值类型
public Func<int,int,string> myFunc = (a1,a2)=>
{
int result = a1+a2;
return "返回值为:"+result;
}
六、协变逆变
- 协变 out
- 某个返回值类型可以用它的子类类型替换,则这个类型支持协变,List不支持协变
- 应用,如:IEnumerable<父类> list= new List<子类>();
- 逆变 in
- 逆变是说某个《输入类型》可以用它的《父类类型替换》
- 应用,如:Action<T>支持逆变,IEnumerable<子类> list= new List<父类>();
七、缓存
- 总结:正常情况下,如果创建一个静态成员和静态构造方法,在第一次使用的时候会初始化,后面再次使用永远不会初始化
- 但是如果我们使用泛型类,当我们传递不同的类型时,静态成员和静态构造,还会在第一次执行
static void Main(string[] args)
{
CacheBaseGeneric<Student>.SaveData(new Student{name = "000"});
CacheBaseGeneric<Student>.GetData().Name;
CacheBaseGeneric<Teacher>.SaveData(new Student{name = "000"});
CacheBaseGeneric<Teacher>.GetData().Name;
//使用静态构造方法,不同类型进入时先进行初始化,当该类型再次进入时则不进入构造方法,直接更新缓存
//总结:正常情况下,如果创建一个静态成员和静态构造方法,在第一次使用的时候会初始化,后面再次使用永远不会初始化
//但是如果我们使用泛型类,当我们传递不同的类型时,静态成员和静态构造,还会在第一次执行
}
//基于泛型实现缓存:泛型类+静态字段+静态方法
//结论:泛型本质就是根据不同的数据类型,编译成不同的类,下面可以实现高性能不同数据类型的数据缓存
public class CacheBaseGeneric<T>where T:class,new()
{
private static T tData = null;
//静态构造方法
static CacheBaseGeneric()
{
Console.writeLine("静态都在方法被调用,类型为:"+typeof(T));
}
//保存数据
public static void SaveData(T data)
{
tData = data;
}
//获取缓存数据
public static T GetData()
{
return tData;
}
}