class Program { static void Main(string[] args) { Person person = new Person(); Person chinese2 = new Chinese();//chinese继承自person,所以允许转换 List<Person> people = new List<Person>(); //以下代码不允许。 //一群中国人难道不是一群人?? //1、list<people>与list<chinese>没有继承关系。 //2、若成立,就可以向这个列表中写入people类型数据,也可以写入chinese类型数据,这是类型不安全的 List<Person> chineses = new List<Chinese>(); //另外一个更容易理解的例子 //所有类都是Object的子类,若这个转换成立,那么list里可以有各种各样的数据。 List<object> list = (List<object>)people; //协变 IMyList<Person> myPeople = new MyList<Chinese>(); myPeople.Item = new Person();//协变的属性是只读的,所以报错 //协变的前提: //1、只有泛型接口和泛型委托才可以协变,详见MyList2类 //2、协变的类型实参只能是引用类型,不能是值类型 IMyList<object> myList1 = new MyList<int>(); } } class Person { public int ID { get; set; } public string Name { get; set; } } class Chinese: Person { public string Gender { get; set; } } /// <summary> /// c#4.0起,使用out 类型参数修饰符允许协变。 /// 协变类型参数只能是只读; /// out修饰符会让编译器验证T是否真的只用作“输出”,且永远不用于形参或属性的赋值方法 /// </summary> /// <typeparam name="T"></typeparam> interface IMyList< out T> { public T Item { get;} /// <summary> /// out 修饰的类型参数必须是只读,所以代码报错 /// </summary> public T Item2 { get; set; } /// <summary> /// out 修饰的类型参数不能做为形参,所以代码报错 /// </summary> /// <param name="t"></param> public void SetValue(T t); } /// <summary> /// 实现接口类 /// </summary> /// <typeparam name="T"></typeparam> class MyList<T> : IMyList<T> { public T Item => default(T); public T Item2 { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } public void SetValue(T t) { } } /// <summary> /// 只有泛型接口和泛型委托才可以协变。泛型类型与结构永远不可协变 /// </summary> /// <typeparam name="T"></typeparam> class MyList2<out T> { }