c#-泛型、协变、逆变

泛型简单介绍:

可以使用泛型声明的元素:类、接口、方法、委托

泛型之前:
泛型之前使用object封装不同类型的参数,缺点:性能差、运行时判断类型(不安全)...
泛型是在编译期间转为实际类型副本,所以性能好,还可以使用约束对泛型进行约束

泛型约束:
约束泛型类型必须满足约束。使用泛型约束后,可以像使用约束类型的方式使用泛型变量

约束种类:
where T:class//引用类型约束
where T:new()//无参构造函数约束,加了此约束后可以使用无参构造函数创建实例:T t = new T();
where T:类//具体类或其子类约束
where T:接口//具体接口或其子类约束
where T:struct//值类型约束

协变逆变:

协变逆变只能放在接口或委托中使用

个人理解:协变逆变可以使我们的代码更灵活,帮我们做了类型转换操作。协变是子类转父类;逆变是父类转子类。

协变(out):修饰返回值,泛型只能出现在成员的返回类型上,不能做传入参数

协变案例:

扫描二维码关注公众号,回复: 8030067 查看本文章
    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>();
   }

猜你喜欢

转载自www.cnblogs.com/fanfan-90/p/11963741.html