zoukankan      html  css  js  c++  java
  • 泛型和协变逆变

    c#中的泛型不支持特例化。所谓特例化就是针对 T  的不同实参,编写特定的代码。因此c#的泛型实际上都是一份代码,不会出现c++中的代码爆炸问题(缺点是让你的exe看起来很小)。唯一的例外是对值类型,因为值类型的大小不一致,所以需要生成新的代码,解决入栈出栈等实现问题,但逻辑上是一致的。

    一、泛型的语法

    二、协变和逆变

    协变这个词是怎么来的?据说是来自数学专业,难怪让人摸不着脑袋。要了解协变逆变,首先要了解类型转化的过程。类型系统支持类型转换,从子类可以转换成基类类型。

    假设子类有成员A,B, 父类有成员A,当子类对象转成父类,也就是客户端会把子类当作父类来用。当使用父类A成员,实际上就是使用子类的A成员,因为子类包含了父类的所有成员,而客户只能通过父类去使用子类,那么就只能使用父类有的成员,不会出现一个成员C,是子类所没有的。因此子类对象就兼容父类。

    反过来就不行,虽然客户使用子类的A,父类也有,但是使用子类的成员B,父类就没有对应的成员,必然就无法执行。假设父类和子类的成员一样,当然可以相互转换,不过这是特殊情况,c#只保证子类转换成父类是安全的,至于父类转换成子类,有任何问题都由程序员自己负责。

    另外一种类型转换是数值类型的转换,原则上是小范围的类型可以转成大范围的类型,这样才不丢失数据。不过,当前的C#还不支持值类型的转换规则用于泛型的协变或逆变。

    协变逆变同样遵从类型转化的规则。c#用out 和 in 修饰泛型参数,支持协变逆变的泛型称为“变体”。out参数用于函数的返回值,in参数用于函数的参数。

    当是out参数的时候:如 out 子类 和out 父类。假设客户使用了父类的返回类型,那么它就要求实际的返回对象自少是父类,或者基于父类的扩展(也就是子类)。假设客户使用了子类的返回类型,那么返回父类的实际对象,当调用子类中存在的成员,而不在父类中存在,必然就是一个错误。

    当是in参数的时候:如in 子类和 in 父类。假设客户使用了父类的参数类型,那么他可以传子类对象实参,也能传父类对象实参进去。但是请注意,实际调用的是子类的函数!那么这个函数实际上就可能用到了子类才有的成员;如果客户把子类对象传进去当然没问题,但是如果客户把父类对象传进去,那么必然就导致错误!和上面有所不同的是,错误产生在对象内部,而不是客户段。

    当使用的是子类的参数类型,客户只能传子类实参,而不能传父类实参,如果实际调用的是子类函数,当然没问题,如果实际调用的父类函数,子类实参可以转化为父类形参,也没有问题。

    用代码说明:

    --------------------------(1)协变

    class B : A;

    A fa(); B fb();

    //客户

    A a = fa() or fb();//ok

    这里面的a 可能是A对象,也可能是B对象,但是客户端只会使用A对象的成员,因此是没有任何问题的。

    B b= fa() or fb();// 

    假设这个也可以,那么b可能是A对象,那么客户端会通过b访问A对象中不存在的成员,因为b是B类型的变量。

    原则就是:实际对象必须是自身或者后代类型,否则无法合理赋值。

    所谓协变,就是实际是fb的对象,但是通过fa访问,既然是通过fa访问,那么客户端就只能是A类型,和前面陈述的情况一致,因此是可行的。

    delegate T f<out T>();

    f<A> fa = ()=>new B(); 

    -------------------------(2)逆变

    class B : A

    void fa(A); void fb(B);

    //客户

    A a;

    B b;

    fa(a) or fa(b) //ok

    fa 函数体是根据形参来定义的,也就是函数体内只使用A的成员。因此A的对象,B的对象都可以传递进去。

    fb(a) or fb(b)

    fb函数体内使用的是B类型,假设A的对象可以传递进去,那么当函数体里面使用了B独有的成员,那不就产生错误了么?

    所谓的逆变,实际就是fa的对象,但是通过fb访问,既然是通过fb访问,那么客户端就只能传入B类型的参数,因此是可行的。

    delegate void f<in T>(T x);

    f<B> fb = (A)=>return;

    fb(b);

    变体有趣的地方是f<A> 和 f<B>完全是独立的类型,没有继承关系,但是却可以“类型转换”,产生类似多态的效果。

    三、应用场合

  • 相关阅读:
    通用权限管理设计 之 数据库结构设计
    jQuery LigerUI 插件介绍及使用之ligerDateEditor
    jQuery LigerUI 插件介绍及使用之ligerTree
    jQuery LigerUI V1.01(包括API和全部源码) 发布
    jQuery liger ui ligerGrid 打造通用的分页排序查询表格(提供下载)
    jQuery LigerUI V1.1.5 (包括API和全部源码) 发布
    jQuery LigerUI 使用教程表格篇(1)
    jQuery LigerUI V1.0(包括API和全部源码) 发布
    jQuery LigerUI V1.1.0 (包括API和全部源码) 发布
    nginx keepalived
  • 原文地址:https://www.cnblogs.com/Nobel/p/2801635.html
Copyright © 2011-2022 走看看