协变(Covariance)与逆变(Contravariance)的入门理解
高级泛型类型系统特性,涉及接口和委托中的类型转换。
协变(out)
- 放宽返回类型
- 正确描述:允许使用比原始类型更具体(派生)的类型
- 如何理解"更具体":子类比父类更丰富,所以“更具体”指的是子类。
- 允许使用"更具体"的返回类型
- 常用于返回类型的场景、泛型集合和接口中。如 `IEnumerable<T>` 就是协变的。
Eg:
### Animal(基类)=>Mamal(子类)=>Lion(子子类)
// 协变:返回类型可以是更具体的类型
interface IAnimalProvider<out T> where T : Animal
{T GetAnimal(); // 返回类型可以更具体
}class LionProvider : IAnimalProvider<Lion>
{public Lion GetAnimal() {return new Lion();}
}class Program
{static void Main() {// 协变:允许将更具体类型的提供者 // 赋值给更基础类型的引用IAnimalProvider<Lion> lionProvider = new LionProvider();IAnimalProvider<Animal> animalProvider = lionProvider; // 允许}
}
逆变(in)
- 放宽参数类型
- 正确描述:允许使用比原始类型更基础(基类)的类型
- 如何理解"更基础":基类是根基,所以“更基础”指的是基类。
- 允许使用"更基础"的输入类型
- 常用于方法参数的场景、委托和事件处理。如 `Action<T>` 和 `Func<T>` 中。
Eg:
### Animal(基类)=>Mamal(子类)=>Lion(子子类)
// 逆变:参数类型可以是更基础的类型
interface IAnimalComparer<in T> where T : Animal
{int Compare(T x, T y); // 参数类型可以更基础
}class MammalComparer : IAnimalComparer<Mammal>
{public int Compare(Mammal x, Mammal y) //放宽参数类型{return 0;}
}class Program
{static void Main() {// 逆变:允许将基础类型的比较器// 赋值给更具体类型的引用IAnimalComparer<Mammal> mammalComparer = new MammalComparer();IAnimalComparer<Lion> lionComparer = mammalComparer; // 允许}
}
总结
特征 | 协变(out) | 逆变(in) |
---|---|---|
关键字 | out | in |
关注点 | 返回类型 | 参数类型 |
类型转换 | 可以使用更具体的返回类型 | 可以接受更基础的参数类型 |
使用场景 | 工厂、提供者 | 比较器、处理器 |
Eg:
// 定义接口interface IAnimal{}class Dog : IAnimal{}class Bulldog : Dog{}#region 协变示例// 使用out关键字定义协变接口interface ICovariantProducer<out T>{T Produce();}class AnimalProducer<T> : ICovariantProducer<T> where T : IAnimal{private T _animal;public AnimalProducer(T animal){_animal = animal;}public T Produce() => _animal;}class Program{static void DemonstrateCovariance(){// 协变:可以将 ICovariantProducer<Bulldog> 赋值给 ICovariantProducer<Dog>ICovariantProducer<Bulldog> bulldogProducer = new AnimalProducer<Bulldog>(new Bulldog());ICovariantProducer<Dog> dogProducer = bulldogProducer;}}#endregion#region 逆变示例// 使用in关键字定义逆变接口interface IContravariantConsumer<in T>{void Consume(T item);}class AnimalConsumer<T> : IContravariantConsumer<T> where T : IAnimal{public void Consume(T animal){Debug.Log($"Consuming an animal: {animal}");}}class Program2{static void DemonstrateContravariance(){// 逆变:可以将 IContravariantConsumer<Dog> 赋值给 IContravariantConsumer<Bulldog>IContravariantConsumer<Dog> dogConsumer = new AnimalConsumer<Dog>();IContravariantConsumer<Bulldog> bulldogConsumer = dogConsumer;}}#endregion