协变和逆变之疑问
前言
关于协变和逆变已经有很多园友谈论过了,学习时也参考过园友们的文章,非常之到位!尤其是园友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);
你所看到的并非事物本身,而是经过诠释后所赋予的意义