图解C#高级教程(四):协变、逆变-2. 逆变

时间:2024-10-03 14:57:52

在C#中,逆变(Contravariance)是与协变相反的特性,允许将基类类型替换为派生类类型。逆变主要用于参数类型的上下文,特别是在方法参数时。通过逆变,我们可以使用更通用的类型来替代特定的类型,从而提高代码的灵活性和可重用性。

2.1 逆变的概念

逆变是指在泛型类型的使用中,允许将某个类型参数替换为该参数的基类。这种特性通常在需要处理不同类型的对象时非常有用。表现在代码上就是某个函数的参数类型是基类类型,但是可以接受其派生类类型的实参。

2.2 语法

在C#中,可以通过使用 in 关键字来声明逆变类型参数。下面是逆变的基本语法:

public delegate void MyDelegate<in T>();

2.3 使用场景

逆变的常见使用场景包括:

  1. 委托:在使用委托时,逆变允许将一个接受派生类的委托赋值给接受基类的委托。
  2. 事件处理:在事件处理程序中,使用逆变来处理不同类型的事件。
  3. 集合操作:在处理集合时,逆变可以帮助简化参数类型的定义。

2.4 代码示例:委托中使用逆变

下面的程序实现了一个基类类型的委托指向参数类型为基类类型的方法,但是在执行委托时,传入给委托的参数类型为派生类类型。

using System;

// 基类
public class Animal
{
    public string Name { get; set; }
}

// 派生类
public class Dog : Animal { }

// 定义一个逆变的委托
public delegate void AnimalAction<in T>(T animal);

class Program
{
    static void Main()
    {
        // 将接受Animal类型的委托赋值给接受Dog类型的委托
        AnimalAction<Animal> animalAction = MakeSound;
        
        Dog dog = new Dog { Name = "Buddy" };
        animalAction(dog);  // 输出: Buddy makes a sound
    }

    static void MakeSound(Animal animal)
    {
        Console.WriteLine($"{animal.Name} makes a sound");
    }
}

2.5 代码示例:事件处理中使用逆变

下面的代码中实现了使用事件和逆变,统一处理不同用户的目的。

    public void AddUser(User user)

输出:

John has been added.
Admin has been added.

使用 in 和 out 关键字只适用于委托和接口,不适用于类、结构和方法。

不包括 in 和 out 关键字的委托和接口类型参数叫做不变。这些类型参数不能用于协变和逆变。