C#提供了5中泛型:类、结构、接口、委托和方法,前四个是类型,方法是成员。
使用where子句约束类型参数
每一个有约束的类型都要自己的where子句。
使用逗号分隔多个约束。
where子句在类型参数列表的关闭尖括号后列出,不使用任何符号分隔,可以以任意次序列出。
约束的类型和顺序
①最多只能有一个主约束,且主约束必须放在第一位。
②可以有任意个接口名约束。
③若存在构造函数约束,必须放在最后。
泛型方法
调用时可不指定尖括号内的类型参数(S、T),编译器会自行根据传入的参数的类型推断类型形参的类型。
泛型委托
类型参数列表包括:返回类型,委托形参,约束子句。
泛型接口
interface IIfc<T> //声明泛型接口
{
T ReturnIt(T val);
}
class MyGenericClass<S> : IIfc<S> //泛型类,继承泛型接口,S需要相匹配
{
//实现接口内的泛型方法
public S ReturnIt(S val){return val;}
}
class MySimpleClass: IIfc<int>, IIfc<string> //继承泛型接口的非泛型类
{
/*无法同时继承泛型接口和指定了类型参数的接口,如: IIfc<int>, IIfc<S>*/
public int ReturnIt(int val){return val;} //实现int类型接口
public string ReturnIt(string val){return val;} //实现string类型接口
}
//Main内:
var intGeneric = new MyGenericClass<int>();
var simple = new MySimpleClass();
Console.WriteLine(intGeneric.ReturnIt(5)) //打印出5
Console.WriteLine(simple.ReturnIt(5)) //打印出5
Console.WriteLine(simple.ReturnIt("Hello world!")) //打印出Hello world!
可变性 Variance
显示变化使用in和out关键字只适用于委托和接口。
class Animal{
public int legCount = 4;
}
class Dog : Animal{...}
delegate T Factory<T>(); //声明泛型委托
//Main
Factory<Dog> dogMaker = () => return new Dog();
Factory<Animal> animalMaker = dogMaker; //错误,两个委托之间并无继承关系
协变 convariance
若只用于输出值(返回值或out参数),在泛型的类型参数列表中添加out
关键字,则可使用父类的泛型接收子类的泛型。
delegate T Factory<out T>(); //声明泛型委托,out关键字表明可以使用协变
//Main
Factory<Dog> dogMaker = () => return new Dog(); //实际构造的委托是使用Dog类类型变量声明的
Factory<Animal> animalMaker = dogMaker; //正常使用
逆变 contravariance
在期望传入基类时,允许传入派生类对象。
若只用于输入,在泛型的类型参数列表添加in
关键字,父类的泛型可以转化为子类的泛型。
delegate void ContraVa<in T>(T a); //声明泛型委托,in关键字代表允许逆变
//Main
ContraVa<Animal> animalContra= (Animal a) => Console.WriteLine(a.legCount);
ContraVa<Dog> dog1 = animalContra; //正常使用
dog1(new Dog);