1、泛型类、泛型方法、泛型接口、泛型委托。
2、用到的设计思想:延迟声明(能推迟做的事情就尽量推迟做)。
3、语法糖:编译器自动帮我们识别类型,泛型不是简单的语法糖,它是框架升级和语法糖的双重结果。
4、泛型就是用一个东西来满足多种不同类型的需求的。
5、引入泛型前使用object作为类型参数有2个问题
1)、装箱拆箱,性能损耗。传入一个int值(栈) ,object又在堆里面,如果把int传递进来,就会把值从栈里面copy到堆里(装箱)。使用的时候,又需要用对象值,又会copy到栈(拆箱)。
2)、类型安全问题,可能会有,因为传递的对象是没有限制的。
6、泛型约束
/* * 五种约束: * * where T:struct 值类型约束:类型参数必须为值类型 * * where T:class 引用类型约束:适用于类、接口、委托、数组等,类型参数必须为引用类型 * * where T:new() new()无参构造器约束:类型参数必须有一个公有的无参构造器 * * where T:<base class name> 基类约束:类型参数必须是指定的基类或是派生自指定的基类 * * where T:<interface> 接口约束:类型参数必须是指定接口或实现指定的接口,可以指定多个接口约束,约束接口也可以是泛型的 * * * 组合约束:用的不多 * 在约束列表中,第一个必须是引用类型约束或者值类型约束,或者是基类约束,然后才是接口约束,最后才是new()约束 * 指定引用类型约束或值类型约束的同时也指定基类约束是非法的 * * 同一个类型形参可以使用多个约束,中间用逗号隔开,例如: * class Test<T> where T : Myclass, Interface, new(){......} * 替换T的类型实参必须是继承Myclass类,且实现Interface接口,且拥有一个无参构造器 * * 在使用两个或多个类型形参时,也可以使用多条where子句分别为它们指定约束 */
下面通过一个简单的例子来看下如何使用
using System; using System.Collections.Generic; using System.Text; namespace ConsoleApp1 { /// <summary> /// 泛型类 /// </summary> public class MyGeneric<T1, T2> where T1 : Person, ISay //T1必须是Person类或者是Person的派生类,并且实现了ISay接口 where T2 : ISky //T2必须是实现了ISky接口 { public void Say(T1 t) { t.Say(t.Name); } public void Sky(T2 t) { t.Sky(); } /// <summary> /// 泛型方法 /// </summary> /// <typeparam name="T3"></typeparam> /// <param name="t"></param> /// <returns></returns> public T3 GetDefault<T3>(T3 t) where T3 : struct { return default(T3); } } /// <summary> /// 人类 /// </summary> public class Person { /// <summary> /// 姓名 /// </summary> public string Name { get; set; } } /// <summary> /// 说接口 /// </summary> public interface ISay { void Say(string name); } /// <summary> /// 飞接口 /// </summary> public interface ISky { void Sky(); } }
7、协变和逆变
1)、二者只使用与泛型委托和泛型接口。
2)、协变:由子类方向 向 父类方向 转变,用out关键字,T类型只能用于返回值。
3)、逆变:由父类方向 向 子类方向 转变,用in关键字,T类型只能用于传入参数。
using System; using System.Collections.Generic; using System.Linq; namespace MyGeneric.Extend { /// <summary> /// 所谓协变逆变,都是跟泛型相关, /// 只能放在接口或者委托的泛型参数前面 /// out 协变covariant 修饰返回值 /// in 逆变contravariant 修饰传入参数 /// </summary> public class CCTest { public static void Show() { //Func<int, string> { Bird bird1 = new Bird(); Bird bird2 = new Sparrow();//子类实例化 麻雀当然是个bird Sparrow sparrow1 = new Sparrow(); //Sparrow sparrow2 = new Bird();//子类变量 不能用父类实例化 } { List<Bird> birdList1 = new List<Bird>(); //List<Bird> birdList2 = new List<Sparrow>(); //一堆麻雀 难道不是 一堆鸟吗? 语义上是可以的 //不成立,语法不通过,原因是List<Bird>是一个类--List<Sparrow>也是一个类,没有父子关系 List<Bird> birdList3 = new List<Sparrow>().Select(c => (Bird)c).ToList(); } //泛型还有不够和谐的地方---泛型不就是为了书写方便 { //协变:就是让右边可以用子类,让泛型用起来更方便 //out修饰,协变后,T只能作为返回值,不能当参数 IEnumerable<Bird> birdList1 = new List<Bird>(); IEnumerable<Bird> birdList2 = new List<Sparrow>(); Func<Bird> func = new Func<Sparrow>(() => null); ICustomerListOut<Bird> customerList1 = new CustomerListOut<Bird>(); ICustomerListOut<Bird> customerList2 = new CustomerListOut<Sparrow>(); customerList2.Get(); } { //逆变:就是让右边可以用父类,让泛型用起来更方便 //in修饰,逆变后,T只能作为当参数 不能做返回值, ICustomerListIn<Sparrow> customerList2 = new CustomerListIn<Sparrow>(); ICustomerListIn<Sparrow> customerList1 = new CustomerListIn<Bird>(); customerList1.Show(new Sparrow()); ICustomerListIn<Bird> birdList1 = new CustomerListIn<Bird>(); birdList1.Show(new Sparrow()); birdList1.Show(new Bird()); Action<Sparrow> act = new Action<Bird>((Bird i) => { }); } { IMyList<Sparrow, Bird> myList1 = new MyList<Sparrow, Bird>(); IMyList<Sparrow, Bird> myList2 = new MyList<Sparrow, Sparrow>();//协变 IMyList<Sparrow, Bird> myList3 = new MyList<Bird, Bird>();//逆变 IMyList<Sparrow, Bird> myList4 = new MyList<Bird, Sparrow>();//协变+逆变 } } } /// <summary> /// 鸟 /// </summary> public class Bird { public int Id { get; set; } } /// <summary> /// 麻雀 /// </summary> public class Sparrow : Bird { public string Name { get; set; } } /// <summary> /// 逆变 /// </summary> /// <typeparam name="T"></typeparam> public interface ICustomerListIn<in T> { //T Get();//不能做返回值 void Show(T t); } public class CustomerListIn<T> : ICustomerListIn<T> { //public T Get() //{ // return default(T); //} public void Show(T t) { } } /// <summary> /// out 协变 只能是返回结果,不能做参数 /// </summary> /// <typeparam name="T"></typeparam> public interface ICustomerListOut<out T> { T Get(); //void Show(T t); } public class CustomerListOut<T> : ICustomerListOut<T> { public T Get() { return default(T); } //public void Show(T t) //{ //} } public interface IMyList<in inT, out outT> { void Show(inT t); outT Get(); outT Do(inT t); ////out 只能是返回值 in只能是参数 //void Show1(outT t); //inT Get1(); } public class MyList<T1, T2> : IMyList<T1, T2> { public void Show(T1 t) { Console.WriteLine(t.GetType().Name); } public T2 Get() { Console.WriteLine(typeof(T2).Name); return default(T2); } public T2 Do(T1 t) { Console.WriteLine(t.GetType().Name); Console.WriteLine(typeof(T2).Name); return default(T2); } } }