C# 类型参数协变与逆变
在C#中,泛型类型参数的协变(Covariance)和逆变(Contravariance)是高级特性,它们允许我们在使用泛型类型时更灵活地处理类型之间的关系。理解这些概念可以帮助你编写更通用、更安全的代码。
什么是协变与逆变?
协变和逆变是描述类型参数在继承关系中的行为方式的概念:
- 协变(Covariance):允许使用比原始类型更具体的类型。例如,如果
IEnumerable<Derived>
可以赋值给IEnumerable<Base>
,那么IEnumerable<T>
就是协变的。 - 逆变(Contravariance):允许使用比原始类型更通用的类型。例如,如果
Action<Base>
可以赋值给Action<Derived>
,那么Action<T>
就是逆变的。
协变与逆变的实际应用
协变示例
协变通常用于返回类型。例如,IEnumerable<T>
接口是协变的,这意味着你可以将一个 IEnumerable<Derived>
赋值给 IEnumerable<Base>
。
csharp
class Base { }
class Derived : Base { }
IEnumerable<Derived> derivedList = new List<Derived>();
IEnumerable<Base> baseList = derivedList; // 协变
在这个例子中,IEnumerable<Derived>
可以赋值给 IEnumerable<Base>
,因为 Derived
是 Base
的子类。
逆变示例
逆变通常用于输入参数。例如,Action<T>
委托是逆变的,这意味着你可以将一个 Action<Base>
赋值给 Action<Derived>
。
csharp
Action<Base> baseAction = (baseObj) => Console.WriteLine(baseObj.GetType().Name);
Action<Derived> derivedAction = baseAction; // 逆变
derivedAction(new Derived()); // 输出: Derived
在这个例子中,Action<Base>
可以赋值给 Action<Derived>
,因为 Base
是 Derived
的父类。
实际案例
协变的应用场景
假设你有一个处理动物列表的应用程序:
csharp
class Animal { }
class Dog : Animal { }
void ProcessAnimals(IEnumerable<Animal> animals)
{
foreach (var animal in animals)
{
Console.WriteLine(animal.GetType().Name);
}
}
IEnumerable<Dog> dogs = new List<Dog> { new Dog(), new Dog() };
ProcessAnimals(dogs); // 协变允许传递 IEnumerable<Dog> 给 IEnumerable<Animal>
在这个例子中,ProcessAnimals
方法可以接受 IEnumerable<Dog>
,因为 IEnumerable<T>
是协变的。
逆变的应用场景
假设你有一个处理事件的系统:
csharp
class Event { }
class MouseEvent : Event { }
void HandleEvent(Action<Event> eventHandler)
{
eventHandler(new Event());
}
Action<MouseEvent> mouseEventHandler = (mouseEvent) => Console.WriteLine("Mouse event handled");
HandleEvent(mouseEventHandler); // 逆变允许传递 Action<MouseEvent> 给 Action<Event>
在这个例子中,HandleEvent
方法可以接受 Action<MouseEvent>
,因为 Action<T>
是逆变的。
总结
协变和逆变是C#中强大的泛型特性,它们允许我们在类型层次结构中更灵活地使用泛型类型。协变主要用于返回类型,而逆变主要用于输入参数。理解这些概念可以帮助你编写更通用、更安全的代码。
附加资源
练习
- 创建一个协变的接口
IEnumerable<T>
并实现它。 - 创建一个逆变的委托
Action<T>
并使用它处理不同类型的事件。 - 尝试在实际项目中应用协变和逆变,观察它们如何提高代码的灵活性。
通过练习,你将更好地掌握协变与逆变的实际应用,并能够在自己的项目中灵活运用这些高级特性。