zoukankan      html  css  js  c++  java
  • 13.3.1 可变性的种类:协变性和逆变性

    1. 协变性:从API返回的值

    协变性用于向调用者返回某项操作的值。例如一个简单的表示工厂模式的泛型接口,它只包含一个方法 CreateInstanse ,返回适当类型的实例。代码如下

    1     public interface IFactory<T>
    2     {
    3         T CreateInstance();
    4     }

    现在, T 在接口中只出现了一次(除了在签名中),它仅作为返回值使用,即方法的输出。
    这意味着可以将特定类型的工厂视为更一般类型的工厂。如在现实世界里,你可以将比萨工厂视为食品工厂。

    2. 逆变性:传入API的值

    逆变性则相反。它指的是调用者向API传入值,即API是在消费值,而不是产生值。
    我们来想象另一个简单的接口——它可以向控制台打印特定的文档类型。

    同样,它也只有一个方法Print :

    1     public interface IPrettyPrinter<T>
    2     {
    3         void Print(T document);
    4     }

    这次 T 只作为参数出现在了接口的输入位置。
    具体而言,如果我们实现了 IPrettyPrinter<SourceCode> ,就可以将其当作 IPrettyPrinter<CSharpCode> 来使用。

    3. 不变性:双向传递的值

    如果协变性适用于仅从API输出值的情况,而逆变性用于仅向API输入值的情况,那么如果值双向传递会如何呢?
    简而言之,什么也不会发生。这种类型是不变体(invariant)。
    下面的接口表示可以对数据类型进行序列化和反序列化的类型:

    1     public interface IStorage<T>
    2     {
    3         byte[] Serialize(T value);
    4         T Deserialize(byte[] data);
    5     }

    这时,如果存在一个具有特定类型 T 的 IStorage<T> 实例,我们不能将其视为该接口更具体或更一般类型的实现。
    如果以协变的方式使用(如将 IStorage<Customer> 视为 IStorage-<Person> ),则可能在调用 Serialize 时传入一个无法处理的对象。
    类似地,如果以逆变的方式使用,则可能在反序列化数据时得到一个预料之外的类型。
    如果有助于理解的话,可以将不变性看成 ref 参数:按引用传递变量,其类型必须与参数本身的类型完全一致,因为值被传入了方法内部,并且同样被高效地传出。

  • 相关阅读:
    数据库连接(1)-从JDBC到MyBatis
    基于 abp vNext 和 .NET Core 开发博客项目
    基于 abp vNext 和 .NET Core 开发博客项目
    正则表达式位置匹配
    正则表达式字符匹配
    2019年终总结
    Win10 1903 运行安卓模拟器蓝屏解决方案
    我已经看到了,撤回也没用了(PC微信防撤回补丁)
    DOCKER 学习笔记1 认识docker
    Java 中级 学习笔记 2 JVM GC 垃圾回收与算法
  • 原文地址:https://www.cnblogs.com/kikyoqiang/p/10099549.html
Copyright © 2011-2022 走看看