泛型接口中的协变与逆变,帮助理解

图片 1

  前日想起了以前看的《深刻明白C#》那本书中的泛型章节,个中对泛型的可变性的精通。泛型可变性分三种:协变和逆变。逆变也又称之为抗变。

新近在看《C#高等编制程序(第九版卡塔尔》那本书,见到了泛型接口那章。在那之中关于协变和逆变没太精通,讲得有一点坑爹,网络查了大多资料,总算(感觉卡塔尔弄精晓了,来此地记录一下。

 怎么知道那八个名词的趣味:

朝气蓬勃、协变和逆变是怎样?

先从字面上精通 协变(Covariance)、逆变(Contravariance)。
co- 是英文中象征“协同”、“协作”的前缀。协变 的字面意思就是“与调换的方向生龙活虎致”。
contra- 是保加利亚共和国语中代表“相反”的前缀,逆变 的字面意思正是是
“与变化趋势相反”。
那便是说难点来了,这里的 变化趋向 指的是怎么?
C# 中对于指标(即对象引用卡塔 尔(英语:State of Qatar),仅设有意气风发种隐式类型转换,即
子类型的目的援用到父类型的目的引用的改换。这里的变化指的正是这种
子->父 的类型调换。
object o = “hello”;
//string (子类卡塔 尔(阿拉伯语:قطر‎类型的引用转换为 object (父类卡塔尔国类型的援用
协变与逆变就算从名字上看是七个完全相反的调换,但事实上只是“子类型援引到父类型援引”那生龙活虎进度在函数中使用的
七个例外阶段 而已,接下去将详细表明那一点。

  ①:协变即为在泛型接口类型中动用out标志的花色参数。协变的字面意思是“与调换的主旋律黄金时代致”②逆变那就是用in来标志的泛型接口类型的项目参数。逆变的字面意思是“与转移的趋向相反”

二、使用函数的不等阶段发生的类型转变

假使有意气风发函数,选取 object 类型的参数,输出 string 类型的再次来到值:

string Method(object o)
{
    return "abc";
}

那就是说在Main函数中大家得以这么调用它:

string s = "abc";
object o = Method(s);

在乎,这里爆发了一次隐式类型转变:

  1. 在向函数输入时,参数 s 由 string 类型转变为 object 类型
  2. 在函数输出(重返卡塔 尔(阿拉伯语:قطر‎时,重回值 由 string 类型转变为 object 类型
    大家这里能够看作是函数签字可发出转移(无论函数的从头到尾的经过,不影响结果卡塔尔国:
  3. string Method(object o) 可转变为 string Method(string o)
  4. string Method(string o) 可转移为 object Method(string o)
    也便是说,在函数输入时,函数的 输入类型 可由 object 转变为
    string,父->子
    在函数输出时,函数的 输出类型 可由string转变为object,子->父

  供给小心的是不管协变依然逆变也一定要在泛型接口中来接受。

三、掌握泛型接口中的 in、out参数

没有一点点名in、out的气象
豆蔻年华经有风流倜傥泛型接口,何况有多少个类实现了此接口:

interface IDemo<T>
{
    T Method(T value);
}
public class Demo : IDemo<string>
{
    //实现接口 IDemo<string>
    public string Method(string value)
    {
        return value;
    }
}

在Main函数中如此写:
IDemo<string> demoStr = new Demo();
IDemo<object> demoObj = demoStr;
地点的这段代码中的第二行包含了二个豆蔻梢头旦:
IDemo<string> 类型能够隐式转变为 I德姆o<object> 类型
那乍看上去有如“子类型援引转换为父类型援用”
相近,可是特别不满,他们并不雷同。倘使能够扩充隐式类型转变,那就意味着:
string Method(string value) 能转换为 object Method(object value)
从上风度翩翩节中大家清楚,在函数那输入和出口阶段,其品种可生成趋向是例外的。所以在C#中,要想使用泛型接口类型的隐式转变,供给研讨“输入”和“输出”二种情景。
接口仅用于出口的事态,协变

interface IDemo<out T>
{
    //仅将类型 T 用于输出
    T Method(object value);
}
public class Demo : IDemo<string>
{
    //实现接口
    public string Method (object value)
    {
        //别忘了类型转换!
        return value.ToString();
    }
} 

在Main函数中那样写:
IDemo<string> demoStr = new Demo();
IDemo<object> demoObj = demoStr;
可将 string Method (object value) 转换为 object Method (object value)
就可以将 I德姆o<string> 类型调换为 IDemo<object> 类型。
仅从泛型的花色上看,那是 “子->父”
的转变,与第后生可畏节中涉嫌的转变方向相通,称之为“协变”。
接口仅用于输入的事态,逆变
同理大家能够给 T 加上 in 参数:

interface IDemo<in T>
{
    //仅将类型 T 用于输入
    string Method(T value);
}
public class Demo : IDemo<object>
{
    //实现接口
    public string Method (object value)
    {
        return value.ToString();
    }
} 

在Main函数中如此写:
IDemo<object> demoObj = new Demo();
IDemo<string> demoStr = demoObj;
此间可将 string Method (object value) 转变为 string Method (string
value)
就可以将 I德姆o<object> 类型调换为 I德姆o<string> 类型。
仅从泛型的类别上看,那是 “父->子”
的转变,与第焕发青新春中提到的转变方向相反,称之为“逆变”,不常也译作“抗变”或“反变”。

  先来举个着力的例子,来增加你对可变性的理解。在C#中有隐式类型转换,举个例子:

四、总结

如上只谈谈了协变与逆变在点子中的情形,其实在质量中状态也周围似,不再表明。
恐怕大家也开掘了,所谓“协”与“逆”都是只是生机勃勃种表象,其内在精气神儿为相符进程。
“协变”与“逆变”中的“协”与“逆”表示泛型接口在将品种参数仅用于输入或输出的事态下,其种类参数的隐式转变所服从的法规。

  string str = "nibian";
  object str1 = str;
  Console.WriteLine(str1);
协变

当泛型接口类型仅用于出口(使用首要词
out卡塔尔,其项目参数隐式调换所依照的法规与指标援引的类型转变规律肖似,称之为“协变”

  

逆变

当泛型接口类型仅用于输入(使用主要词
in卡塔尔国,其类别参数隐式转换所遵从的法规与目的援引的类型转变规律相反,称之为“逆变”、“抗变”或“反变”。

图片 1

  大家都清楚string类型是object类型的子类型,即string->object为子->父;从子类型到父类型的更改是隐式类型转变。

发表评论

电子邮件地址不会被公开。 必填项已用*标注