1.5.4 泛型接口(协变和抗变)

使用了泛型接口,我们不再像以前那样去处理一些方法,比如:

以前版本中存在这样一个方法:

public interface IComparable<in T>
{
    int CompareTo(T other);
}


public class Person: IComparable
{
    public int CompareTo(object obj)
    {
        Person other = obj as Person;
        return this.lastname.CompareTo(other.LastName);
    }
}

调用CompareTo方法时,需要对obj进行强制类型转换,但是有了泛型之后,就不在使用这用方法了

public class Person: IComparable<Person>
{
    public int CompareTo(Person other) =>
    LastName.CompareTo(other.LastName);
//...

上面用到了in的参数,其实还有out的参数IEnumerator<out T>.,接下来我们就会讲解这些内容

1、协变和抗变(逆变)

.net 4为泛型接口和泛型委托添加了重要的更改:协变和抗变。

协变:类似于子类到父类的转换称之为协变 Sharp sharp = new Rectange();

逆变:类似于父类到子类的转换称之为逆变 Rectange sharp = new Sharp();

以上只是简单的定义,还没有明确下来,那么究竟如何应用协变和逆变呢?

1.1协变

书中内容看起来着实费劲,此处参考https://blog.csdn.net/sudazf/article/details/17148971

首先明确一个问题,在.net 4.0之前,注意看代码的注释

Sharp sharp = new Rectange();//可以编译通过,以为Rectange继承了Sharp

IEnumerable<Sharp> sharps = new List<Rectange>();//但是不能这样写,因为当时不支持泛型的转换

那么问题来了,在.net 4.0之后为什么就可行了呢?

public interface IEnumerable<out T> : IEnumerable

是因为在T参数中加了一个out 关键字,此out关键字,和方法中的out关键字不同。

下面呢我们来看一下什么时候使用协变。

首先,定义一个接口

     public interface ICovariant<T>
    {

    }

在定义两个类,分别为父类和子类,都继承第一个接口ICovariaant<T>

    public class Sharp:ICovariant<Sharp>
    {

    }
    public class Rectange:Sharp,ICovariant<Rectange>
    {

    }

然后开始调用:

我们看到,让泛型子类,赋值给父类的时候报错,那么我们就需要对接口进行修改,加上out参数,构成泛型的协变

     public interface ICovariant<out T>
    {

    }

此时编译通过。

这样我们就可以说接口ICovariant只是对类型T的协变,也就是说支持泛型子类赋值给泛型父类。

1.2 抗变(逆变)

当我们将 ICovariant<Sharp>的实例变量赋值给 ICovariant<Rectange>实例变量时,则编译不通过。

这是属于父类赋值给子类,属于抗变,那么我们将接口修改为 in 修饰的参数

    public interface ICovariant<in T>
    {

    }

此时编译通过。

1.3逆变和抗变应用的特点。

我们在接口中添加两个方法,第一个方法返回T类型,第二个方法,T类型作为方法的输入参数。

    public interface ICovariant<out T>
    {
        T Method1();
        void Method2(T param);
    } 

这时我们就会发现

将T类型作为方法2的输入参数类型会报错。

报错的原因为,因为类型T为协变,不能用于抗变的位置。这时我们就会发现,out类型只能用于输出类型的修饰(协变),不能用于输入类型的修饰(抗变)。

那么我们将泛型的协变类型改为逆变类型:

果然和我们想的一样,这时in 修饰的T类型,用于方法1的返回类型就会报错。

那么我们该同时使用协变和逆变呢?我们需要将方法分开到两个接口

    public interface ICovariant<out T>
    {
        T Method1();
        void Method3(IContravariant<T> param);
    }
 
    public interface IContravariant<in T>
    {
        void Method2(T param);
    }

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值