• 协变和逆变之疑问


    前言

    关于协变和逆变已经有很多园友谈论过了,学习时也参考过园友们的文章,非常之到位!尤其是园友LoveJenny的,参看时自己也有敲代码加理解,但是出现一个问题,甚是不解,请看下面。【注】这个问题可能对您而言很简单,若有解释,请告知,在此感谢。高手绕道!

    既然是标题是协变和逆变,还是先给个公认的msdn概念吧。说完概念直接进入问题区。

    概念

    协变:是指能够使用与原始指定的派生类型相比,派生程度更大的类型。

    逆变:则是指能够使用派生程度更小的类型。

    问题

    请看代码

    1     public class Employee
    2     {
    3        
    4     }
    5 
    6     public class Programmer : Employee
    7     {
    8 
    9     }

    再看定义的接口以及实现

     1     interface ISalary<out T>
     2     {
     3         T pay();
     4         void otherpay(T t);       
     5     }
     6 
     7     public class BaseSalaryCounter<T> : ISalary<T>
     8     {
     9         public T pay()
    10         {
    11             return default(T);
    12         }
    13 
    14         public void otherpay(T t)
    15         {
    16             
    17         }
    18     }

    再在控制台中调用

    ISalary<Programmer> pro = new BaseSalaryCounter<Programmer>();
                
    ISalary<Employee> emp = pro;

    毫无疑问出现错误,如下:【注】若不明白错误原因请参考园友LoveJenny文章

    但是现在我这样做,注意下面红色部分!

     1     interface ISalary<out T>
     2     {
     3         T pay();
     4         void otherpay<T>(T t);       
     5     }
     6 
     7     public class BaseSalaryCounter<T> : ISalary<T>
     8     {
     9         public T pay()
    10         {
    11             return default(T);
    12         }
    13 
    14         public void otherpay<T>(T t)
    15         {
    16             
    17         }
    18     }

    再在控制台调用就生成成功了!不是说的out着重于的是返回值,而in着重于的是作为参数吗,这里有个无返回值并且有参数的方法otherpay()方法,根据上面第一个是错误的,修改成这样怎么就对了呢??怎么没出现上图错误呢???才疏学浅,百思不得其解,希望得到令人信服的解释!

    问题解决 

    【注】泛型参数T在被套另一动作后其可变性会被扭转。

    总结

    (1)引入协变(out)和逆变(in)是为了解决类型安全。

    (2)若泛型参数处于输出的位置,那它的协变性是类型安全的。

    (3)若泛型参数处于输入的位置,则它的逆变性一般是类型安全的。(说的是一般情况下,更多请参考资料)

     补充

    逆变(in)典型用法

     1            /*定义接口*/
     2    public interface IMyComparable<in T>
     3     {
     4         int Compare(T other);
     5     }
     6       /*Employee为基类并实现其接口*/
     7    public class Employee : IMyComparable<Employee>
     8     {
     9         public string Name { get; set; }
    10         public int Compare(Employee other)
    11         {
    12             return Name.CompareTo(other.Name);
    13         }
    14     }
    15 
    16       /*Programmer继承Employee并实现其接口*/
    17     public class Programmer : Employee, IMyComparable<Programmer>
    18     {
    19 
    20         public int Compare(Programmer other)
    21         {
    22             return Name.CompareTo(other.Name);
    23         }
    24     }
    25  
    26       /*Manager继承Employee*/
    27     public class Manager : Employee
    28     {
    29 
    30     }
    31 
    32       /*定义方法*/
    33 
    34     static void Test<T>(IMyComparable<T> t1, T t2)
    35     {
    36 
    37     }
    38 
    39       /*调用*/
    40 
    41       Programmer p = new Programmer() { Name = "Mike" };
    42       Manager m = new Manager() { Name = "Steve" };
    43       Test(p, m);
  • 相关阅读:
    新手Cocoa&Objectivec的进阶
    设计模式六大原则
    仿IOS Launch 欢迎界面
    新手开发IOS的疑惑,待补充
    Windows xp系统Hal.dll文件损坏的解决办法
    上班五年了!总结一下收获篇
    关于理财:摘自“华夏基金网”
    《雪》
    上班五年了!总结一下性格篇
    索尼爱立信M608C使用心得!
  • 原文地址:https://www.cnblogs.com/CreateMyself/p/4695725.html
Copyright © 2020-2023  润新知