美文网首页.NET
C# 泛型委托的 逆变与协变

C# 泛型委托的 逆变与协变

作者: Gascognya | 来源:发表于2021-05-10 02:55 被阅读0次

先说两个引子

1,类型的向上转型和向下转型

Animal类型 转为 Dog 类型为向下转型,反之。

2,泛型的转型问题

List<Dog> 不能转为 List<Animal>

为了解决上述问题,C#提供了逆变与协变的关键字,in和out。

干嘛用的?

用来声明泛型是否允许向上或向下转型。

和函数参数上的in和out关键字是否相同?

有些许联系,但完全不一样。


普通泛型上的应用在此略过,我们直接说泛型委托上的。

泛型委托的in与out

例如Func的定义的一种

public delegate TResult Func<in T, out TResult>(T arg)

在这里,请问in和out的含义是什么?

为什么要这样写? 不写行不行?

我直接说我的理解:

in代表允许T类型向下转型,out代表允许TResult类型向上转型。

可以不写,不写之后不支持转型。

例如我们列出三个继承关系的class

Object, Animal, Dog

列出两种泛型委托

delegate T FunA<out T>

delegate void FunB<in T>(T arg)

这是两种简单的in和out的情况。

我们可以分别进行尝试

FunA<Animal> a1 = () => new Animal();

FunA<Dog> a2 = a1; //报错

FunA<Object> a3 = a1;

作为一个老练的程序员,你应该能很容易看出来,第二句是有风险的。

如果该语句能执行:

Dog d = a2(); 好像没问题,但是实际上它得到的是父类Animal的实例。这将是会报错的向下转型。还好这种事编译器不会让其发生。

所以说,返回值的类型,是不可以向下转的。

因为我这个函数牌子上承诺返回Animal, 你却给我挂了个返回Dog的牌子,那怎么能行,我办不到。

所以得出结论,返回值的类型不可以向下转型(逆变,in),只可以用out修饰,或者干脆不修饰。

那么in呢?

FunB<Animal> b1 = ani => ani.someMethod();

FunB<Dog> b2 = a1;

FunB<Object> b3 = a1;//报错

我这个b1函数内,要调用Animal类型的方法

如果给我套个Object的签名,假设b3(new Object())成立。

那就是到Object实例里找Animal的方法。很明显有出错的可能。

所以得出结论,参数类型不可以向上转型(协变,out),只能用in来修饰,或者干脆修饰。

所以

网上有些文章写,因为是参数所以用in,因为是返回值所以用out。是搞错了因果关系。

因为参数不可以协变,所以不可以用out,只能用in或者不写

因为返回值不可以逆变,所以不可以用in,只能用out或者不写


至于in和out是命名上的巧合,还是微软有意为之方便大家记忆,就无从得知了


但如果想不被复杂的概念搞混,稀里糊涂的记住。搞清其内部真实原因是很有必要的。


半夜床上手机码的字,排版不好还请见谅

相关文章

  • Kotlin学习笔记 - 泛型

    1. 基本用法 2. 型变 型变包括 协变、逆变、不变 三种: 协变:泛型类型与实参的继承关系相同 逆变:泛型类型...

  • 泛型编程中的型变

    在泛型编程中,经常会提到型变。型变分为两种:协变与逆变。协变covariant表示与泛型参数T的变化相同,而逆变c...

  • C# 中泛型接口的协变和逆变(抗变)

    在C#中声明泛型接口时,我们可以使用 in 和 out 参数来控制这个泛型是协变还是逆变的,这里逆变有时也被翻译成...

  • Java协变和逆变

    泛型的协变与逆变 协变与逆变用来描述类型转换(type transformation)后的继承关系,其定义如下:如...

  • Scala 通俗易懂 ---- 协变、逆变、不变

    协变、逆变、不变 Scala 语言中协变、逆变、不变是指拥有泛型的类型,在声明和赋值时的对应关系 协变:声明时泛型...

  • JAVA泛型与类型安全

    1. 基础泛型 2. 协变与逆变与不变 协变 简单来说即: Java中的数组是协变的 逆变与协变相对,逆转了类型关...

  • C# 泛型委托的 逆变与协变

    先说两个引子 1,类型的向上转型和向下转型 Animal类型 转为 Dog 类型为向下转型,反之。 2,泛型的转型...

  • Scala 泛型协变与泛型边界

    代码准备 泛型协变 泛型协变、逆变、不变是指拥有泛型的类在声明和赋值时的对应关系。 协变:声明时泛型是父类,赋值时...

  • Java 泛型与通配符

    参考地址:《Java 泛型,你了解类型擦除吗?》 《Java中的逆变与协变》 《java 泛型中 T、E .....

  • Java中的桥接方法与泛型的逆变和协变

    泛型的协变和逆变是什么?对应于Java当中,协变对应的就是,而逆变对应的就是

网友评论

    本文标题:C# 泛型委托的 逆变与协变

    本文链接:https://www.haomeiwen.com/subject/njjbdltx.html