委托让方法参数化,而泛型实现了类型参数化。
一、泛型类型的声明规则:
1、在类名称后跟一对尖括号,括号中为若干个类型参数,多个类型参数之间使用逗号进行分隔,类型参数实际上是个类型占位符。如、public class MyClass<T>{},T只是个习惯,实际上用其他字母也完全可以。
2、在类声明的主体中使用类型参数来表示应该被替代的类型,一般是方法的参数类型,返回类型,或者作为字段、属性的类型。
示例1:
public class MyClass<T1, T2> { public T1 field1; //在类内部泛型类型还能用 public T2 field2; public T1 GetField1() //作为返回值 { return field1; } public T2 GetField2() { return field2; } public void SetField1(T1 data) //作为方法参数类型 { field1 = data; } public void SetField2(T2 data) { field2 = data; } }
泛型能够根据传入的不同类型,实施不同的处理。重用了代码逻辑,将类型抽象了出来。
泛型的类型约束,通过约束能够对类型实参添加一定的限制条件,约束是通过使用上下文关键字的where应用的,只需要在泛型类型声明的尖括号后面使用where关键字,后面紧跟类型参数和约束类型,中间使用冒号分隔即可。
类型约束一共有6种,如下所示:
约束类型 | 说明 |
where T : class | 类型实参必须是引用类型,包括任何类、接口、委托或数组类型 |
where T : struct | 类型实参必须是值类型,可以是任何值类型,但不包括Nullable |
where T : <基类名> | 类型必须是指定的类或者它的派生类 |
where T : <接口名> | 类型必须是实现了指定的接口或者实现了该接口的类型,可以指定多个接口约束,约束接口也可以是泛型的 |
where T : new() | 类型实参必须有一个无参数的公共构造函数 |
where T : U | 类型实参T必须是类型实参U,或者是U的派生类,这称作裸类型约束 |
同时还必须要注意,当需要添加多个类型约束时,约束之间用逗号分隔。同时对于某一个类型参数的多种约束类型,where字句与where字句之间没有次序要求,但是对于where字句内部是有次序要求的。具体次序如下:
- 如果有class,struct,基类这三种类型约束,则必须放在第一位。
- 之后是接口约束,数量不限
- 如果有new(),则必须放在最后。
如:
public class TestType<T,V> where T : Person where V : new(){} //where与where字句没有次序要求 public class TestType<T> where T : class,IList,new(){} //where字句内部有类型要求
class Program { static void Main(string[] args) { Person P = new Person(); P.Id = 1; P.Name = "张三"; TestType<Person> tt = new TestType<Person>(); string str = tt.getType(P); Console.WriteLine(str); //输出张三 Console.ReadKey(); } } public class TestType<T> where T : Person //指定实参类型必须是Person类或Person类的派生类 { public string getType(T data) { return data.Name; } } public class Person { public int Id; public string Name; }
泛型方法与泛型类很相似。一下给出两个泛型方法的例子。
class Program { static void Main(string[] args) { Person p = new Person(); p.Id = 1; SetName<Person>(p); Console.WriteLine(p.Name); //输出张飞 Console.ReadKey(); } public static Person SetName<T>(T per) where T : Person { per.Name = "张飞"; return per; } } class Person { public int Id { get; set; } public string Name { get; set; } } class Program { static void Main(string[] args) { string str = "你好!"; Console.WriteLine(GetMessage<string>(str)); //输出System.String Console.ReadKey(); } public static Type GetMessage<T>(T Message) { return Message.GetType(); } }
泛型的扩展方法,与扩展方法一样,只是有点怪异罢了。给个示例:
class Program { static void Main(string[] args) { Person<string> per = new Person<string>(); per.Person<string>("关羽"); //这样子来调用扩展方法,自己都看不懂牛得一B Console.WriteLine(per.Name); Console.ReadKey(); } } public static class Set { public static void Person<T>(this Person<T> p, T Name) { p.Name = Name; } } public class Person<T> { public int Id { get; set; } public T Name { get; set; } }
泛型委托和非泛型委托也很相似,只是泛型委托进行了一层抽象,将中间涉及的操作类型以及返回值类型抽象为了类型参数,以便更大限度地复用该委托。
public delegate T PrintDelegate<T>(T data); class Program { static void Main(string[] args) { PrintDelegate<string> StrDelegate = PString; //委托的定义中,3个大T都是string string outStr = StrDelegate("我是一个兵"); //调用委托 Console.WriteLine(outStr); //输出委托返回值 我是一个兵我是一个兵 PrintDelegate<int> IntDelegate = PInt; //类型参数传入int,则参数类型,返回值类型,都是int int outInt = PInt(3); //由于参数类型设为了int,因此只能绑定参数跟返回值为int的方法 Console.WriteLine(outInt); //输出 6 Console.ReadKey(); } public static string PString(string str) { return str + str; } public static int PInt(int i) { return i + i; } }
泛型的协变与逆变