C#中协变逆变的实现

发布时间:2026/5/24 6:55:57

C#中协变逆变的实现 1. 协变与逆变的概念协变Covariance允许将子类派生类类型作为父类基类类型使用。例如IEnumerablestring 可以被视为 IEnumerableobject因为 string 是 object 的子类。按照前面我们在继承中学习的里氏替换原则父类装子类是不是就非常的合理因为一定会确保类型安全嘛。逆变Contravariance允许将父类类型作为子类类型使用。例如Actionobject 可以被视为 Actionstring因为 object 是 string 的父类。你看居然父类可以变成子类你想想你的父亲有一天居然可以化形为你的儿子来使用是不是就很反常识不过这种转化肯定是有限制滴不然啥都可以转化是不是就整个面向对象就乱成了一锅粥。核心思想在类型安全的前提下允许更灵活的泛型类型转换。2. 协变与逆变的作用及作用对象作用提 高泛型接口和委托的灵活性使其能更自然地处理继承关系。减少强制 类型转换增强代码的可读性和安全性。作用对象泛型接口如 IEnumerableT泛型委托如 FuncT、ActionT不适用类、结构体或方法参数仅支持接口和委托。请务必记住协变逆变的作用对象仅仅只能在泛型接口和泛型委托中使用在其他的地方是万万不行滴不然就会天下大乱啦3. 协变与逆变的关键字out关键字协变标记泛型类型参数为协变表示该参数仅用于输出位置如返回值。啥意思就是说T这个泛型类型在被out修饰了以后他就只能被当成返回值的类型了不能当做函数中传参时候的类型了为什么呢因为你总要做些区分嘛要先列好规矩互相才能正常运行嘛不然你玩儿你的我打我打的整个继承和多态就乱成了一锅粥。1interfaceICovariantoutT { T GetItem(); }in关键字逆变标记泛型类型参数为逆变表示该参数仅用于输入位置如方法参数。啥意思就是说T这个泛型类型在被in修饰了以后他就只能被当成函数传参时候的类型了不能当做返回值类型。1interfaceIContravariantinT {voidProcess(T item); }4. 泛型接口与委托的示例示例1协变在泛型接口中的体现12345678910111213141516171819202122// 协变接口定义interfaceIAnimaloutT{T GetAnimal();}classAnimal { }classDog : Animal { }classAnimalShelter : IAnimalAnimal{publicAnimal GetAnimal() newAnimal();}classDogShelter : IAnimalDog{publicDog GetAnimal() newDog();}// 使用协变IAnimalAnimal shelter newDogShelter();// 合法DogShelter → AnimalShelterAnimal animal shelter.GetAnimal();// 安全获取Animal类型示例2逆变在泛型接口中的体现123456789101112131415161718192021222324// 逆变接口定义interfaceIFeederinT{voidFeed(T animal);}classAnimal { }classDog : Animal { }classAnimalFeeder : IFeederAnimal{publicvoidFeed(Animal animal) Console.WriteLine(Feeding animal);}classDogFeeder : IFeederDog{publicvoidFeed(Dog dog) Console.WriteLine(Feeding dog);}// 使用逆变IFeederDog feeder newAnimalFeeder();// 合法AnimalFeeder → DogFeederfeeder.Feed(newDog());// 安全传递Dog类型给需要Animal的方法//打印Feeding animal示例3协变在泛型委托中的体现12345// 协变委托delegateT FactoryoutT();FactoryDog dogFactory () newDog();FactoryAnimal animalFactory dogFactory;// 合法Dog → AnimalAnimal animal animalFactory();示例4逆变在泛型委托中的体现12345// 逆变委托delegatevoidHandlerinT(T obj);HandlerAnimal animalHandler (Animal a) Console.WriteLine(Handle animal);HandlerDog dogHandler animalHandler;// 合法Animal → DogdogHandler(newDog());// 安全调用总结特性关键字方向适用场景协变out子类→父类返回值、集合遍历如 IEnumerableT逆变in父类→子类方法参数、回调处理如 ActionT协变out修饰的泛型替代符只能作为返回值不能作为参数逆变in修饰的泛型替代符只能作为参数不能作为返回值协变父类委托容器可以装 子类泛型委托容器逆变子类委托容器可以装 父类泛型委托容器注意事项协变类型参数必须仅用于返回值位置。逆变类型参数必须仅用于方法参数位置。不支持类的协变/逆变仅限接口和委托。

相关新闻