协变和逆变之疑问

前言

关于协变和逆变已经有很多园友谈论过了,学习时也参考过园友们的文章,非常之到位!尤其是园友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);
复制代码

 


为了方便大家在移动端也能看到我分享的博文,现已注册个人公众号,扫描上方左边二维码即可,欢迎大家关注,有时间会及时分享相关技术博文。

感谢花时间阅读此篇文章,如果您觉得这篇文章你学到了东西也是为了犒劳下博主的码字不易不妨打赏一下吧,让楼主能喝上一杯咖啡,在此谢过了!
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!
本文版权归作者和博客园共有,来源网址:http://www.cnblogs.com/CreateMyself)/欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
posted @   Jeffcky  阅读(976)  评论(3编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示