当前位置:首页 > C# > 正文

深入理解C#泛型委托的协变与逆变(小白也能掌握的C#委托covariance contravariance实战指南)

在C#编程中,泛型委托是提升代码复用性和灵活性的重要工具。而协变(covariance)逆变(contravariance)则是泛型委托中常被初学者忽略但极其强大的特性。本文将用通俗易懂的方式,带你从零开始掌握C#泛型委托的协变与逆变应用。

深入理解C#泛型委托的协变与逆变(小白也能掌握的C#委托covariance contravariance实战指南) C#泛型委托 协变逆变 委托covariance contravariance C#委托教程 第1张

什么是协变与逆变?

简单来说:

  • 协变(out):允许你使用“更派生”的类型作为返回值。例如,一个返回 Animal 的方法可以赋值给返回 Dog 的委托(前提是 Dog 继承自 Animal)。
  • 逆变(in):允许你使用“更通用”的类型作为参数。例如,一个接受 Animal 参数的方法可以赋值给接受 Dog 参数的委托。

C#中的泛型委托

C# 提供了两个内置泛型委托:Func<TResult>Action<T>。它们分别用于有返回值和无返回值的方法。

其中:

  • Func<out TResult> 支持协变(注意 out 关键字)
  • Action<in T> 支持逆变(注意 in 关键字)

协变实战示例

假设我们有以下类结构:

public class Animal{    public virtual string Speak() => "...";}public class Dog : Animal{    public override string Speak() => "汪汪!";}public class Cat : Animal{    public override string Speak() => "喵喵!";}

现在我们定义一个返回 Animal 的方法,并将其赋值给 Func<Dog> 委托:

// 返回 Animal 的方法static Animal GetAnimal() => new Dog();// 协变:Func<Animal> 可以赋值给 Func<Dog>Func<Dog> getDog = GetAnimal; // ✅ 合法!因为 Dog 是 Animal 的子类Dog myDog = getDog();Console.WriteLine(myDog.Speak()); // 输出:汪汪!

这就是协变的力量——它让泛型委托更加灵活。

逆变实战示例

再来看逆变。我们定义一个接受 Animal 参数的方法:

// 接受 Animal 参数的方法static void FeedAnimal(Animal animal){    Console.WriteLine($"喂 {animal.GetType().Name} 吃饭!");}// 逆变:Action<Animal> 可以赋值给 Action<Dog>Action<Dog> feedDog = FeedAnimal; // ✅ 合法!因为 Dog 是 Animal 的子类feedDog(new Dog()); // 输出:喂 Dog 吃饭!

这里,虽然 FeedAnimal 接受的是 Animal,但我们却能把它当作 Action<Dog> 使用。这就是逆变——参数类型可以“向上兼容”。

为什么需要协变与逆变?

协变和逆变让 C# 泛型委托更符合“里氏替换原则”(Liskov Substitution Principle),即子类对象可以替换父类对象而不破坏程序逻辑。通过 outin 关键字,C# 在编译期就保证了类型安全,同时提升了代码的通用性。

总结

- C#泛型委托FuncAction 内置支持协变与逆变。

- 协变(out)用于返回值,允许“更具体的类型”。

- 逆变(in)用于参数,允许“更通用的类型”。

- 正确使用这些特性,可以写出更灵活、更安全的 C# 代码。

无论你是刚接触 C#委托教程 的新手,还是想深入理解 委托covariance contravariance 的开发者,掌握协变与逆变都将极大提升你的编程能力。希望这篇关于 C#泛型委托 的文章对你有所帮助!