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> { }