c#泛型参数 协变和逆变

可以参考 https://www.cnblogs.com/qixuejia/p/4383068.html 我的测试代码如下:

  public class Animal { }
    public class Dog : Animal { }

    public class testclass
    {
        public int i = 1;
    }
 //协变和 逆变
            Func<Object,bool> parent = (p)=>{Console.WriteLine(p.GetType().FullName.ToString());return true;};
            Func<testclass, bool> child = parent;

            child(new testclass());

            //Func<testclass, bool> chx = (cp) => { Console.WriteLine(cp.GetType().FullName.ToString()); return true; };
            ////Func<Object, bool> phx = chx;  //此句有问题
            //Func<Object, bool> phx = (Func<Object, bool>)chx; //换成这句就编译成功,但运行时出错。
            //phx(new testclass());

            Func<bool, testclass> ch = (b) => { var t = new testclass(); Console.WriteLine("t.i=" + t.i); return t; };
            Func<Boolean, Object> ph = ch;
            ph(false);


            List<Dog> lsdog = new List<Dog>();
            //List<Animal> lsanimal = lsdog;//无法转换
            List<Animal> lsanimal = lsdog.Select(d => { return (Animal)d; }).ToList();//可以正常转换,但这种做法太麻烦

            List<Animal> lsanimal1 = new List<Animal>();
            //List<Dog> lsdog1 = lsanimal1; //也无法转换

            //List<T>中没有用到in和out关键字,所以List<>没有协变和逆变功能。用IEnumerable<out T>来看看
            List<Animal> lsanimal2 = new List<Animal>();
            IEnumerable<Animal> ieanimal = lsanimal2; //子类转换成父接口当然成功(只不过是相同的泛型而已)
            //IEnumerable<Dog> iedog = ieanimal;//不成功 为什么不成功呢?因为IEnumerable<out t>中用的是out关键字,代表以后转换时,只能进行输出转换,既然
            //是输出转换,如果是子转换成父(协变)就可以成功,如果是父转子(逆变)就不能成功。

            List<Dog> lsdog2 = new List<Dog>();
            IEnumerable<Dog> iedog = lsdog2;//也是相同泛型参数的子类转换成父接口,当然成功
            IEnumerable<Animal> ieanimal2 = iedog; //协变,泛型参数子转换成父。成功


            //out关键字指出可以协变,in指出可以逆变
            //c#中IEnumerable<out T>,IEnumerator<out T>,IQueryable<out T>都是可以协变的
            //IComparer<in T>,ICompareable<in T>是可以逆变的

猜你喜欢

转载自my.oschina.net/u/2963604/blog/1818464