泛型简单介绍:
可以使用泛型声明的元素:类、接口、方法、委托
泛型之前:
泛型之前使用object封装不同类型的参数,缺点:性能差、运行时判断类型(不安全)...
泛型是在编译期间转为实际类型副本,所以性能好,还可以使用约束对泛型进行约束
泛型约束:
约束泛型类型必须满足约束。使用泛型约束后,可以像使用约束类型的方式使用泛型变量
约束种类:
where T:class//引用类型约束
where T:new()//无参构造函数约束,加了此约束后可以使用无参构造函数创建实例:T t = new T();
where T:类//具体类或其子类约束
where T:接口//具体接口或其子类约束
where T:struct//值类型约束
协变逆变:
协变逆变只能放在接口或委托中使用
个人理解:协变逆变可以使我们的代码更灵活,帮我们做了类型转换操作。协变是子类转父类;逆变是父类转子类。
协变(out):修饰返回值,泛型只能出现在成员的返回类型上,不能做传入参数
协变案例:
public class Bird { public string ID { get; set; } } public class Sparrow : Bird { public string Name { get; set; } } static void Main(string[] args) { Bird bird = new Sparrow();//正确,一只麻雀就是一只鸟 List<Bird> birdList = null; //birdList = new List<Sparrow>();//报错,一群麻雀和一群鸟没有继承关系 //只能用下面这两种方式 birdList = new List<Sparrow>().Select(s=>(Bird)s).ToList();//方式1 birdList = new List<Sparrow>().Cast<Bird>().ToList();//方式2 //上面这两种方法写起来比较麻烦,所以有了协变,协变就是解决这个问题
//为什么下面这个没有报错 IEnumerable<Bird> iBirdList = new List<Sparrow>(); //就是因为IEnumerable<out T>接口是支持协变的,协变使用out关键字 }
逆变与协变相反,是父类转换子类,使用in关键字。泛型类型只能出现在传入参数上
逆变案例:
public interface ICustomerEnumerable<in T> { } public class CustomerEnumerable<T> : ICustomerEnumerable<T> { } static void Main(string[] args) { //in 逆变 ICustomerEnumerable<Sparrow> sparrowList = new CustomerEnumerable<Bird>(); }