zoukankan      html  css  js  c++  java
  • 小菜学习逆变与协变

    协变与逆变

    2013年10月9日19:00:00

    关于接口的协变与逆变

      1     class Program
      2 
      3     {
      4 
      5         static void Main(string[] args)
      6 
      7         {
      8 
      9  
     10 
     11             //协变   IDataServices<Student>类型对象 变成 IDataServices<Person> 
     12 
     13             //泛型的子类 变成泛型的 父类 ,但是需要注意2个接口 不存在继承关系 只是编译器 允许这么写 CLR并提供支持,实际上是语法糖
     14 
     15             // 此处调用GetDate 返回值类型为Person;原因: 因为 gDS 传入 泛型的约束 是 Person 而这个方法 返回是 T 所以..
     16 
     17             //  这个比较好理解 例如 object a = "1";
     18 
     19             IGetDataServices<Person> gDS = GetDataServices();
     20 
     21             Person ans = gDS.GetData();    
     22 
     23             Console.WriteLine(ans);
     24 
     25            
     26 
     27             //逆变 将 泛型父类型复制给 泛型子类型 很诧异的方式 但是编译器确实允许这种存在
     28 
     29             // 同上 他们不存在 继承关系 编译器允许这样写 CLR底层 提供支持
     30 
     31             // SaveDate 方法 调用 是 安全的 因为逆变 只允许 传入对象是 ,类如Student,接受对象为Person, 类似:Person p=new Student,这明显就是多态的 子类实例被父类类型使用..
     32 
     33             // 例如说 string i= new object(); 这是错误的
     34 
     35             ISetDateServices<Student> sDs = SetDateServices();
     36 
     37             sDs.SaveData(ans as Student);
     38 
     39            
     40 
     41             //空格
     42 
     43             Console.ReadKey();
     44 
     45         }
     46 
     47  
     48 
     49         public static IGetDataServices<Student> GetDataServices()
     50 
     51         {
     52 
     53             return new StudentServices();
     54 
     55         }
     56 
     57  
     58 
     59         public static ISetDateServices<Person> SetDateServices()
     60 
     61         {
     62 
     63             return new PersonServices();
     64 
     65         }
     66 
     67     }
     68 
     69  
     70 
     71    
     72 
     73  
     74 
     75     public  class Person
     76 
     77     {
     78 
     79         public Person()
     80 
     81         {
     82 
     83            
     84 
     85         }
     86 
     87  
     88 
     89         public string Name { get; set; }
     90 
     91  
     92 
     93         public override string ToString()
     94 
     95         {
     96 
     97             return Name;
     98 
     99         }
    100 
    101     }
    102 
    103  
    104 
    105     public class Student:Person
    106 
    107     {
    108 
    109        public Student()
    110 
    111        {
    112 
    113           
    114 
    115        }
    116 
    117  
    118 
    119         public string SchoolName { set; get; }
    120 
    121  
    122 
    123        public override string ToString()
    124 
    125        {
    126 
    127            return base.ToString()+"|"+SchoolName;
    128 
    129        }
    130 
    131     }
    132 
    133  
    134 
    135     public interface IGetDataServices<out T>
    136 
    137     {
    138 
    139         T GetData();
    140 
    141     }
    142 
    143  
    144 
    145     public class StudentServices : IGetDataServices<Student>
    146 
    147     {
    148 
    149  
    150 
    151         public Student GetData()
    152 
    153         {
    154 
    155             return new Student()
    156 
    157             {
    158 
    159                Name = "Rufus",
    160 
    161                SchoolName = "Ms"
    162 
    163             };
    164 
    165         }
    166 
    167     }
    168 
    169  
    170 
    171     public interface ISetDateServices<in T>
    172 
    173     {
    174 
    175         void SaveData(T item);
    176 
    177     }
    178 
    179  
    180 
    181     public class PersonServices : ISetDateServices<Person>
    182 
    183     {
    184 
    185         public void SaveData(Person item)
    186 
    187         {
    188 
    189             Console.WriteLine("保存成功:" + item);
    190 
    191         }
    192 
    193 }
    194 
    195  
    View Code

    总结… 

    逆变: 对于接口而言 是传入一个对象 (in)关键字 ,它允许将 父类型泛型接口赋值给 子类型泛型接口 ,例如 例子中的ISetDateServices <in T>, 但是由于是 传入类型约束,所以是安全的…因为调用方法的时候 方法接收的参数为父类型.

    协变: 对于接口而言 是传出 一个对象(out)关键字,他允许 将 子类型泛型赋值给父类型,例如例子中的 IGetDateServices<out T> , 传出类型被约束为父类型,实际传出的类型为子类型.

    总体来说 都是 多态的提现 都是 将 父类变量指向子类型实例的值. 例如:object o=1; 只不过 逆变 多绕了一下. 而协变就好理解一些

  • 相关阅读:
    User-Introduction——介绍
    UserHow to Config
    DevHacking
    【转载】常备JS操作
    【转载】本地搜索服务全面评测
    User-Data config
    小知识:常用到的软件或服务及其使用的端口
    网页配色方案
    User-Validation User Guide
    Dev-Introduction
  • 原文地址:https://www.cnblogs.com/rufus-hua/p/3360296.html
Copyright © 2011-2022 走看看