问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

c#协变 逆变.解决什么问题

发布网友 发布时间:2022-04-27 13:39

我来回答

2个回答

懂视网 时间:2022-04-27 18:00

关于协变和逆变要从面向对象继承说起。继承关系是指子类和父类之间的关系;子类从父类继承所以子类的实例也就是父类的实例。比如说Animal是父类,Dog是从Animal继承的子类;如果一个对象的类型是Dog,那么他必然是Animal。
协变逆变正是利用继承关系 对不同参数类型或返回值类型 的委托或者泛型接口之间做转变。我承认这句话很绕,如果你也觉得绕不妨往下看看。
如果一个方法要接受Dog参数,那么另一个接受Animal参数的方法肯定也可以接受这个方法的参数,这是Animal向Dog方向的转变是逆变。如果一个方法要求的返回值是Animal,那么返回Dog的方法肯定是可以满足其返回值要求的,这是Dog向Animal方向的转变是协变。
由子类向父类方向转变是协变 协变用于返回值类型用out关键字
由父类向子类方向转变是逆变 逆变用于方法的参数类型用in关键字
协变逆变中的协逆是相对于继承关系的继承链方向而言的。
一. 数组的协变:
代码如下:
Animal[] animalArray = new Dog[]{};

上面一行代码是合法的,声明的数组数据类型是Animal,而实际上赋值时给的是Dog数组;每一个Dog对象都可以安全的转变为Animal。Dog向Animal方法转变是沿着继承链向上转变的所以是协变
二. 委托中的协变和逆变
1.委托中的协变
代码如下:
//委托定义的返回值是Animal类型是父类
public delegate Animal GetAnimal();
//委托方法实现中的返回值是Dog,是子类
static Dog GetDog(){return new Dog();}
//GetDog的返回值是Dog, Dog是Animal的子类;返回一个Dog肯定就相当于返回了一个Animal;所以下面对委托的赋值是有效的
GetAnimal getMethod = GetDog;

2.委托中的逆变
代码如下:
//委托中的定义参数类型是Dog
public delegate void FeedDog(Dog target);
//实际方法中的参数类型是Animal
static void FeedAnimal(Animal target){}
// FeedAnimal是FeedDog委托的有效方法,因为委托接受的参数类型是Dog;而FeedAnimal接受的参数是animal,Dog是可以隐式转变成Animal的,所以委托可以安全的的做类型转换,正确的执行委托方法;
FeedDog feedDogMethod = FeedAnimal;

定义委托时的参数是子类,实际上委托方法的参数是更宽泛的父类Animal,是父类向子类方向转变,是逆变
三. 泛型委托的协变和逆变:
1. 泛型委托中的逆变
如下委托声明:
代码如下:
public delegate void Feed<in T>(T target);

Feed委托接受一个泛型类型T,注意在泛型的尖括号中有一个in关键字,这个关键字的作用是告诉编译器在对委托赋值时类型T可能要做逆变
代码如下:
//先声明一个T为Animal的委托
Feed<Animal> feedAnimalMethod = a=>Console.WriteLine(“Feed animal lambda”);
//将T为Animal的委托赋值给T为Dog的委托变量,这是合法的,因为在定义泛型委托时有in关键字,如果把in关键字去掉,编译器会认为不合法
Feed<Dog> feedDogMethod = feedAnimalMethod;

2. 泛型委托中的协变
如下委托声明:
代码如下:
public delegate T Find<out T>();

Find委托要返回一个泛型类型T的实例,在泛型的尖括号中有一个out关键字,该关键字表明T类型是可能要做协变的
代码如下:
//声明Find<Dog>委托
Find<Dog> findDog = ()=>new Dog();

//声明Find<Animal>委托,并将findDog赋值给findAnimal是合法的,类型T从Dog向Animal转变是协变
Find<Animal> findAnimal = findDog;

四. 泛型接口中的协变和逆变:
泛型接口中的协变逆变和泛型委托中的非常类似,只是将泛型定义的尖括号部分换到了接口的定义上。
1.泛型接口中的逆变
如下接口定义:
代码如下:
public interface IFeedable<in T>
{
void Feed(T t);
}

接口的泛型T之前有一个in关键字,来表明这个泛型接口可能要做逆变
如下泛型类型FeedImp<T>,实现上面的泛型接口;需要注意的是协变和逆变关键字in,out是不能在泛型类中使用的,编译器不允许
代码如下:
public class FeedImp<T>:IFeedable<T>
{
    public void Feed(T t){
        Console.WriteLine(“Feed Animal”);
    }
}

来看一个使用接口逆变的例子:
代码如下:
IFeedable<Dog> feedDog = new FeedImp<Animal>();

上面的代码将FeedImp<Animal>类型赋值给了IFeedable<Dog>的变量;Animal向Dog转变了,所以是逆变
2.泛型接口中的协变
如下接口的定义:
代码如下:
public interface IFinder<out T>
{
    T Find();
}

泛型接口的泛型T之前用了out关键字来说明此接口是可能要做协变的;如下泛型接口实现类
代码如下:
public class Finder<T>:IFinder<T> where T:new()
{
    public T Find(){
        return new T();
    }
}
//使用协变,IFinder的泛型类型是Animal,但是由于有out关键字,我可以将Finder<Dog>赋值给它
IFinder<Animal> finder = new Finder<Dog>();

协变和逆变的概念不太容易理解,可以通过实际代码思考理解。这么绕的东西到底有用吗?答案是肯定的,通过协变和逆变可以更好的复用代码。复用是软件开发的一个永恒的追求。

热心网友 时间:2022-04-27 15:08

协变:协变强调的是泛型类型方法的返回值向后兼容。如果向后兼容那么派生程度将更大。例如Person可以兼容Student,Employee。


逆变:逆变强调的是泛型类型方法的形参值向前兼容。如果向前兼容那么派生程序将更小。例如Employee可以与Person,但与Student不兼容。


协变与逆变的出现的主要是为了解决隐式转换问题

声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
...先讲女主的灵魂飘荡了一段时间,然后重生,请问是那本? 拯救者散热器怎么开 电脑如何一键还原系统电脑一键还原怎么操作 神舟笔记本电脑怎么重新设置神舟战神bios恢复出厂设置 神舟电脑恢复出厂设置神舟战神怎么恢复原厂系统 水泥楼梯如何铺木楼梯 家里面楼梯是水泥的不想铺地毯或者地砖还能铺什么 楼梯的水泥台阶上可以铺地板革吗 手机腾讯会议共享屏幕播放视频没声 腾讯会议共享屏幕没声音怎么办 济南7月份92#汽油价格 在哪里可以下载到微软拼音输入法体验版? 能打出繁体字的微软拼音输入法的下载地址 济南哪儿汽油价格最低 汽油价格真的降了吗? ——→济南今天的汽油价格 济南汽油多少钱一升 如何生儿子的机率高呢?哪些方法可以提高概率,能行不 有什么技巧提高生儿子的概率的?生男孩的最佳时期是什么呢? 如何提高生儿子的概率 C#的逆变和协变我这样理解可以吗 逆变和协变到底有什么区别 高级技校毕业生 面试简历(学历)怎么填 公司要填简历,我有个技工毕业证,学历该怎么填? 高级技工毕业的填简历要填什么学历? .NET 关于泛型的协变和逆变中 in &#47; out 两个参数(或者方法) 的使用方法和什么时候需要使用。求例子。 自投虎口是什么生肖? 羊入虎口四口吞,一龙一蛇飞云天.猜一种动物生肖 小心翼翼蛇追马,羊入虎口凶险多,还请大师指点一下是什么动物呢! 羊入虎口鸡马平故事重演四推三代表什么动物? 甜椒牛肉怎么做 请问下蒜苔甜椒牛肉丝的做法? 甜椒牛肉炒饭怎么做? 如何用生牛肉做熟牛肉求解 帮忙解释一下.net里Func&lt;TResult&gt;的意思 每天平板支撑一分钟,做五次。加慢跑大概三千米左右,一个月可以瘦多少斤? 平板支撑1分钟2次是什么意思? 计算机器的基本目标是什么? 可信计算的发展 计算机的发展目标 计算机安全的三个重要目标是什么 协变和抗变的意思 作文 我们班的牛人 初中作文 《晒晒我们班的“牛人”》 初中作文《我们班的牛人》1000字 中学生晒晒我们班的牛人作文有关口才 以 因为有了 为半命题作文600字速求 因为集体有了我 作文600字大学生 作文:因为有了我(要写我帮助同学的一件事)550~600字 不会写啊,明天就要... 因为有——我更——作文600字初二