C#精通之路——逆变与协变
从C#4.0开始,泛型接口和泛型委托都支持协变和逆变,由于历史原因,数组也支持协变。
里氏替换原则:任何基类可以出现的地方,子类一定可以出现
协变(out)
-
协变:及自然的变化,遵循里氏替换原则,表现在代码上则是任何基类都可以被其子类赋值,如Animal = Dog、Animal = Cat
-
使用out关键字声明(注意和方法中修饰参数的out含义不同)。
-
被标记的参数类型只能作为方法的返回值(包括只读属性)
在没有协变时:
abstract class Animal {}
class Dog : Animal {}
class Cat : Animal {}
interface IPoppable<T>
{
T Pop();
}
class MyStack<T> : IPoppable<T>
{
private int _pos;
private readonly T[] _data = new T[100];
public void Push(T obj) => _data[_pos++] = obj;
public void T Pop() => _data[--_pos];
}
下面的代码在编译时会出错,
var dogs = new MyStack<Dog>();
IPoppable<Animal> animals1 = dogs; // compile error
Stack<Animal> animals2 = dogs; // compile error
此时,如果需要为动物园饲养员新增一个输入参数为Stack饲喂的方法,一个比较好的方法是新增一个约束泛型泛型方法:
class Zookeeper
{
public static void Feed<T>(IPoppable<T> animals) where T : Animal {}
//or
public static void Feed<T>(Stack<T>

本文介绍了C#中泛型的逆变与协变概念,从C#4.0开始,泛型接口和委托支持此特性。协变允许将子类型赋值给基类型,逆变则允许将基类型赋值给子类型。文中通过示例详细解释了如何声明和使用协变泛型接口和委托,以及逆变泛型接口和委托,强调了类型安全的重要性。
最低0.47元/天 解锁文章
1835

被折叠的 条评论
为什么被折叠?



