一.什么是泛型
泛型其实就是一个不确定的类型,可以在类或方法上使用。泛型在声明期间没有明确定义类型,编译后生成一个占位符,只有在调用后传入类型,才会将该确切的类型将占位符替换掉。
二.泛型的定义
//用在类中 public class ClassName<CName> { //用在方法中 public void Mothed<MName>() { } //泛型类中具体使用CName //返回值为CName并且接受一个类型为CName类型的对象 public CName GetC(CName c) { } }
这里的CName和MName是可变的类型(名字也是可变),可以让调用者来决定要使用的类型。
三.使用
下面举个例子。
public class Animal { //会跑的方法 public virtual void CanRun() { Console.WriteLine("Animal Run Can"); } } public class Dog : Animal { //重写父类方法 public override void CanRun() { Console.WriteLine("Dog Can Run"); } } public class Cat : Animal { //重写父类方法 public override void CanRun() { Console.WriteLine("Cat Can Run"); } }
再定义一个animalHouse来存放所有的动物。
public class AnimalHouse { private List<Animal> animals = new List<Animal>(); //添加方法 public void AddAnimal(Animal a) { animals.Add(a); } }
AnimalHouse可以存放所有的动物,但如果取出来,使用就有些不方便。现在放进去Dog和Cat,你可以将所有动物都带出来跑步。假如Dog有个方法是Canswin()游泳的方法,那这里是调用不了,animal没有这个方法。
如果使用泛型的话,就可以由调用者决定使用哪种类型。在AnimalHouse将所有animal改为泛型。
public class AnimalHouse<T> { private List<T> animals = new List<T>(); //添加方法 public void AddAnimal(T a) { animals.Add(a); } }
AnimalHouse想存放什么类型,由调用者决定。
//声明存放所有Dog类型的集合 AnimalHouse<Dog> dog = new AnimalHouse<Dog>(); //声明存放所有Cat类型的集合 AnimalHouse<Cat> cat = new AnimalHouse<Cat>();
传入哪个类型,原本的T就会编译成具体的类型。animalHouse可以让我们来自己构造存放哪种动物的集合。该集合就可以具体使用集合中动物特有的方法。
这里还有个问题,原本AnimalHouse只能存放animal,现在是泛型T,那就算是非animal的类也可以存进去,不符合最初的设计。所以为了类型安全,需要对传入的类型进行约束。
四.泛型约束
泛型约束就是对泛型(传入的类型)进行约束,约束就是指定该类型必须满足某些特定的特征,例如可以被实例化,实现Animal类等。举个例子。
class Base { } class Test<T, U> where U : struct where T : Base, new() { }
使用的话,只需要在泛型后面加上where来使用。
where T : struct。类型必须为值类型。
where T : class。类型必须为引用类型。
where T : new()。类型参数必须具有公共无参数构造函数。 与其他约束一起使用时,new()
约束必须最后指定。
where T : <基类名>。类型参数必须是指定的基类或派生自指定的基类。
where T : <接口名称>。类型参数必须是指定的接口或实现指定的接口。 可指定多个接口约束。 约束接口也可以是泛型。
然后,我们来为AnimalHouse添加泛型约束为:必须包含公共无参构造函数和基数必须为Animal。
//Animal约束T必须是Animal的子类或者本身,new()约束放在最后 public class AnimalHouse<T> where T : Animal, new() { private List<T> animals = new List<T>(); //添加方法 public void AddAnimal(T a) { //调用CanRun方法 //如果不加Animal泛型约束是无法调用.CanRun方法的,因为类型是不确定的 a.CanRun(); animals.Add(a); } }
现在AnimalHouse类限制要传入的参数是,必须继承Animal,且有公共无参构造函数的。