zoukankan      html  css  js  c++  java
  • .NET泛型中的协变与逆变

    泛型的可变性:协变性和逆变性

    实质上,可变性是以一种类型安全的方式,将一个对象作为另一个对象来使用。

    我们已经习惯了普通继承中的可变性:例如,若某方法声明返回类型为Stream,在实现时可以返回一个MemoryStream。泛型可变性的概念与此相同,但要略微复杂一些。可变性应用于泛型接口和泛型委托的类型参数中,这一点必须引起注意。

    可变性有两种类型:协变性和逆变性。二者概念基本相同,只是在上下文中转换的方向不同。

    我们先从协变性开始,它通常要好理解一些。

    • 协变性:从API返回的值

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

      

        /// <summary>
        /// 使用out关键字表示协变
        /// </summary>
        /// <typeparam name="T"></typeparam>
        interface IFactory<out T>
        {
            T CreateInstance();
        }

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

    • 逆变性:传入API的值

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

      

        /// <summary>
        /// 使用in关键字表示逆变
        /// </summary>
        /// <typeparam name="T"></typeparam>
        interface IPrettyPrinter<in T>
        {
            void Print(T document);
        }

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

    不变性:双向传递的值

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

        /// <summary>
        /// 泛型类型的不变性,既不用 in 关键字限制,也不用 out 关键字限制
        /// </summary>
        /// <typeparam name="T"></typeparam>
        interface IStorage<T>
        {
            byte[] Serialize(T value);
    
            T Deserialize(byte[] data);
        }

    这时,如果存在一个具有特定类型T的IStorage<T>实例,我们不能将其视为该接口更具体或更一般类型的实现。如果以协变的方式使用(如将IStorage<Customer>视为IStorage<Person>),则可能在调用Serialize时传入一个无法处理的对象。

    类似地,如果以逆变的方式使用,则可能在反序列化数据时得到一个预料之外的类型。如果有助于理解的话,可以将不变性看成ref参数:按引用传递变量,其类型必须与参数本身的类型完全一致,因为值被传入了方法内部,并且同样被高效地传出。

    更多

    详见MSDN:https://docs.microsoft.com/zh-cn/dotnet/standard/generics/covariance-and-contravariance

  • 相关阅读:
    求两个字符串中相同的汉字及字母的个数
    将十进制转成十六进制
    综合模糊查询
    求第一个字符串中第二个串的个数
    去除字符串中连续的分割符
    去除字符串中的html标记及标记中的内容
    sql基础语句
    SQL Server2008函数大全(完整版)
    sql 数字转人民币大写函数(两种方法)
    数字转IP地址函数
  • 原文地址:https://www.cnblogs.com/WinHEC/p/Covariance_and_Contravariance_and_Invariance.html
Copyright © 2011-2022 走看看