精通C#之逆变与协变

本文介绍了C#中泛型的逆变与协变概念,从C#4.0开始,泛型接口和委托支持此特性。协变允许将子类型赋值给基类型,逆变则允许将基类型赋值给子类型。文中通过示例详细解释了如何声明和使用协变泛型接口和委托,以及逆变泛型接口和委托,强调了类型安全的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C#精通之路——逆变与协变

从C#4.0开始,泛型接口和泛型委托都支持协变和逆变,由于历史原因,数组也支持协变。

里氏替换原则:任何基类可以出现的地方,子类一定可以出现

协变(out)
  • 协变:及自然的变化,遵循里氏替换原则,表现在代码上则是任何基类都可以被其子类赋值,如Animal = Dog、Animal = Cat

  • 使用out关键字声明(注意和方法中修饰参数的out含义不同)。

  • 被标记的参数类型只能作为方法的返回值(包括只读属性)

在没有协变时:

abstract class Animal {}
class Dog : Animal {}
class Cat : Animal {}

interface IPoppable<T>
{
    T Pop();
}

class MyStack<T> : IPoppable<T>
{
    private int _pos;
    private readonly T[] _data = new T[100];
    
    public void Push(T obj) => _data[_pos++] = obj;
    public void T Pop() => _data[--_pos];
}

下面的代码在编译时会出错,

var dogs = new MyStack<Dog>();
IPoppable<Animal> animals1 = dogs; // compile error
Stack<Animal> animals2 = dogs; // compile error

此时,如果需要为动物园饲养员新增一个输入参数为Stack饲喂的方法,一个比较好的方法是新增一个约束泛型泛型方法:

class Zookeeper
{
    public static void Feed<T>(IPoppable<T> animals) where T : Animal {}
    //or
    public static void Feed<T>(Stack<T> 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值