1、泛型类型:泛型类、泛型方法、泛型委托
//泛型类 public class GenericClass<T> { public void GetTypes() { Console.WriteLine(typeof(T).Name); } } public class GenericTypeClass { //泛型方法(指定参数) public void GetVoidType<M>() { Console.WriteLine(typeof(M).Name); } //泛型方法(不指定参数) public void GetEntityType<M>(M t, string name) { Console.WriteLine(t.GetType().Name + name); } //泛型委托(用于泛型参数),只能在泛型类里申明 public delegate void Delegation<T>(T t); //默认三种泛型委托 //带参数,没有返回类型 public Action<string,int> WriteAction = (string s,int a) => Console.WriteLine(s+a); //带参数,有返回类型 public Func<string,bool> FuncTionFunc = (string s)=>string.IsNullOrWhiteSpace(s); //一个参数,只返回bool类型 public Predicate<string> Predication = (string str) => string.IsNullOrWhiteSpace(str); //泛型集合 public Dictionary<string,object> GenericDictionary = new Dictionary<string,object>(); public HashSet<string> GenericHashSet = new HashSet<string>(); }
2、泛型约束
//泛型约束 //值类型参数约束 public void MethodOfStructArgument<T>(T t) where T : struct { } //引用类型参数约束 public void MethodOfObjectArgument<T>(T t) where T : class { } //参数必须有无参构造方法 public void MethodOfNoArgument<T>(T t) where T : new() { } //接口约束 public void MethodOfInterface<T>(T t) where T : 接口名称 { } //父类约束 public void MethodOfFather<T>(T t) where T : 父类名称 { }
3、协变与逆变
//协变逆变只用于泛型接口或泛型委托
现存例子
Cat c = new Cat(); Animal c2 = new Cat(); //用父类接收子类,没问题 List<Cat> catList = new List<Cat>(); //List<Animal> animalList = new List<Cat>(); //编译不通过,因为虽然Animal是Cat的父类,语义正确但是编译器不允许,但是List<Animal>却不是List<Cat>的父类,没有直接的父子关系 IEnumerable<Animal> animalList = new List<Cat>();//编译通过
查看IEnumerable接口,采用了out关键字,协变
public interface IEnumerable<out T> : IEnumerable { new IEnumerator<T> GetEnumerator(); }
委托类型Func也用到了协变
Func<Animal> animalFunc = new Func<Cat>(() => new Cat());
查看Func定义
public delegate TResult Func<out TResult>();
自定义实现
建立父子类
public class Animal { public void breathe() { Console.WriteLine("呼吸"); } } public class Cat:Animal { public void CatchJerry() { Console.WriteLine("抓老鼠"); } }
2.1协变
//协变 IFoo<父类> = IFoo<子类>;左边类型参数是父类,右边类型参数是子类
//要求 T(类型参数)只能是返回值,不能是类型参数
自定义泛型接口fatherInterface及子类sonClass,及说明
public interface fatherInterface<out T> { T getT(); //只能作为返回值,不能作为参数 // void run(T t);//只能作为返回值,不能作为参数 } public class sonClass<T> : fatherInterface<T> { public T getT() { return default(T); } } fatherInterface<Animal> animals = new sonClass<Animal>(); Animal an = animals.getT();//得到的是右边的子类类型,后续若有子类类型调用父类方法肯定是类型安全的
2.2逆变
//逆变:IBar<子类> = IBar<父类>;左边类型参数是子类,右边类型参数是父类
//要求 T(类型参数)只能用于参数,不能是返回值
public interface fatherInterface1<in T> { //T getT(); //只能作为参数,不能作为返回值 void run(T t);//只能作为参数,不能作为返回值 } public class sonClass1<T> : fatherInterface1<T> { public void run(T t) { } } fatherInterface1<Cat> cats = new sonClass1<Animal>(); cats.run(new Cat());//编译器编译时,以左边的参数类型为基准为Cat,所以run方法的参数要传Cat类型,这个方法真实运行时,只要求参数能满足右边类型-Animal即可,Cat一定是Animal所以也没有运行风险