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

 

posted on 2020-08-26 17:20  ilyyin  阅读(397)  评论(0编辑  收藏  举报