C# 泛型中协变和逆变

协变和逆变都是术语,前者指能够使用比原始指定的派生类型的派生程度更大(更具体的)的类型,后者指能够使用比原始指定的派生类型的派生程度更小(不太具体的)的类型。 泛型类型参数支持协变和逆变,可在分配和使用泛型类型方面提供更大的灵活性。

协变 convariance

样例01

//基类
class Animal{
    public int Legs=4;
}

//派生类
class Dog:Animal{

}

delegate T Factory<T>();

class Program{
    static Dog MakeDog{
        return new Dog();
    }

    static void Main(){
        Factory<Dog> dog=MakeDog;
        Factoru<Animal> animal=dog;//这里编译会报错

        Console.WriteLine(animal().Legs.ToString());
    }
}

上述代码编译器会报错,Main 方法第二行,提示不能隐式把右边类型转换为左边类型。

Dog 是 Animal 的派生类,但委托 Factory<Dog> 没有从 Factory<Animal> 派生。相反,两个委托对象是同级的,它们都是 delegate 类型派生。

再仔细分析一下,我们可以看到如果类型参数只用做输出值,则同样的情况也适用于任何泛型委托。对于所有这样的情况,我们应该可以使用派生类创建委托类型,这样应该能够正常工作,因为调用代码总是期望得到一个基类的引用,这也正是它会得到的。

如果派生类只是用于输出值,那么这种结构化的委托有效性之间的常数关系叫协变。 为了让编译器知道这是我们的期望,必须使用 out 关键字标记委托生命中的类型参数。

为该实例中的委托增加 out 关键字,代码就可以通过编译。

delegate T Factory<out T>();

逆变 contravariance

样例02

//基类
class Animal{
    public int Legs=4;
}

//派生类
class Dog:Animal{

}

delegate void Factory<in T>(T a);

class Program{
    static void ShowLegs(Animal a){
        Console.WriteLine(a.Legs);
    }

    static void Main(){
        Factory<Animal> animal=ShowLegs;
        Factoru<Dog> dog=animal;

        dog(new Dog());
    }
}

和之前的情况相似,默认情况下不可以赋值两种不兼容的类型。但是和之前情况也相似的是,有一些情况可以让这些赋值生效。

这种在期望传入基类时允许传入派生对象的特性叫做逆变。 可以在类型参数中显式的使用 in 关键字来表示。

delegate void Factory<int T>(T a);

接口中的协变和逆变

现在你应该已经理解了协变和逆变可以应用到委托上。其实相同的原则也可以应用到接口上,可以在声明接口的时候使用 outin 关键字。

样例03

class Animal { public string Name; }
class Dog : Animal {};

interface IMyIfc<out T>{
    T GetFirst();
}

class SimpleReturn<T>:IMyIfc<T>{
    public T[] items=new T[2];
    public T GetFirst(){ return items[0]; }
}

class Program{
    static void DoSomething(IMyIfc<Animal> returner){
        Console.WriteLine(returner.GetFirst().Name);
    }

    static void Main(){

        SimpleReturn<Dog> dog=new SimpleReturn<Dog>();
        dog.items[0]=new Dog(){ Name="hashiqi" };
        IMyIfc<Animal> animal=dog;
        DoSomething(animal)
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值