协变与逆变
前言
在C#编程中,由于存在类型之间的强制转换,很容易会出现所谓的类型可变性说法,存在协变、逆变、不变三种。
如果创建了泛型类型的实例,编译器会接受泛型类型声明以及类型参数来创建构造类型。但是在日常使用过程中,我们可能会将派生类型分配给基类型的变量,有时候会出现错误。
这里就存在一个赋值兼容性问题。
每一个变量都有一种类型,可以将派生类对象的实例赋值给基类变量(好比之前子类声明的变量可以赋值给父类声明的变量一样)。
如下所示:
//子类赋值给父类
People ahui = new People();
People people = new APeople();
Console.WriteLine("Age:" + people.Age);
//父类
class People
{
public int Age = 27;
}
//子类
class APeople : People
{
}
协变
我们按照同样的逻辑,在泛型委托中进行这种强类型的转换,会发现即使基类和派生类之间可以进行正常的转换,但是委托之间不能进行转换会出现异常错误提示。
具体如下代码所示:
实现:
//协变
delegate T AgeDelegate< T>();
public class Covariance
{
public static APeople GetAge()
{
return new APeople();
}
}
调用:
//外部调用
AgeDelegate<APeople> aPeople = Covariance.GetAge;
AgeDelegate<People> people = aPeople;
上面代码直接报红提示错误:
这就是上面解释的那样子,基类和派生类之间可以进行转换但是委托之间未存在关联,无法进行强制类型的转换。那么想解决这个问题就引入了协变来解决。
如果派生类只是用于输出值,那么这种结构化的委托有效性之间的常数关系叫做协变,可通过主动告知编译器我们的期望,使用Out关键字标记委托声明中的类型参数。
只需要在泛型委托T前加上out修饰,修改成如下这样子后,上面错误演示的代码编译器就可以正常编译通过了。
delegate T AgeDelegate<out T>();
逆变
其实逆变就是在委托中既要声明委托类型,也要在委托方法中有实参。
这种在期望传入基类时允许传入派生对象的特性叫做逆变。逆变使用关键字in来标记。
具体如下代码所示:
实现:
//逆变
delegate void AgeDelegate<in T>(T p);
public class Inversion
{
public static void GetAge(People p)
{
Console.WriteLine(p.Age);
}
}
调用:
AgeDelegate<People> aPeople = Inversion.GetAge;
AgeDelegate<APeople> people = aPeople;
people(new APeople());
本文来自博客园,作者:码农阿亮,转载请注明原文链接:https://www.cnblogs.com/wml-it/p/16534323.html
技术的发展日新月异,随着时间推移,无法保证本博客所有内容的正确性。如有误导,请大家见谅,欢迎评论区指正!
开源库地址,欢迎点亮:
GitHub:https://github.com/ITMingliang
Gitee: https://gitee.com/mingliang_it
GitLab: https://gitlab.com/ITMingliang
建群声明: 本着技术在于分享,方便大家交流学习的初心,特此建立【编程内功修炼交流群】,为大家答疑解惑。热烈欢迎各位爱交流学习的程序员进群,也希望进群的大佬能不吝分享自己遇到的技术问题和学习心得!进群方式:扫码关注公众号,后台回复【进群】。