C# 泛型的協變

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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章