概念
协变:以out修饰的泛型类型叫做协变类型,协变只能返回(当返回值),用于返回参数,协变T只能用来当返回值使用
逆变:以in修饰的泛型类型叫做逆变类型,逆变只能当参数传进来,用于接收参数,逆变T只能用来当参数传递
协变和逆变都是单向的。in可读不可写,out可写不可读
创建两个类,基类:Person,子类:Student
public class Person
{
public int Id { get; set; }
public string UserName { get; set; }
}
public class Student : Person
{
}
协变
我们发现,如下代码会报错,虽然里氏转换子类可以给父类,但是这里不行,因为ListList<Person> persons = new List<Student>();
但是,这样就可以,因为List实现了IEnumerable接口,也就是继承了IEnumerable,根据里氏转换,可以将子类赋值给父类,而且IEnumerableIEnumerable<Person> persons = new List<Student>();
原理是因为IEnumerable本身就是协变,它里面的泛型用out进行修饰了。
协变:父类接收子类
我们模仿IEnumerable接口做个测试。,创建一个协变接口和实现这个接口
//协变接口
public interface IMyOut<out T>
{
T GetT();
}
//实现协变接口
public class MyOut<T> : IMyOut<T>
{
public T GetT()
{
return default(T);
}
}
再Main里调用发现没问题
IMyOut<Person> persons = new MyOut<Student>();
persons.GetT();
逆变:子类接收父类
//逆变接口
public interface IMyIn<in T>
{
void GetT(T t);
}
//实现逆变接口
public class MyIn<T> : IMyIn<T>
{
public void GetT(T t)
{
}
}
IMyIn<Student> students = new MyIn<Person>();
students.GetT(
new Student()
{
Id = 1,
UserName = "张三"
});