美文网首页.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是命名上的巧合,还是微软有意为之方便大家记忆,就无从得知了


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


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

    相关文章

      网友评论

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

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