协变和逆变

 

协变:派生类=>基类

假设有这样一个类:

    class Person : ICloneable
    {
        public object Clone()
        {
            Console.WriteLine("this is Clone");
            return new Person();
        }
    }

但是由于我们知道是返回一个Person类的实例,所以返回类型 object 写在这里总会觉得很别扭,我们希望写成: 

    class Person : ICloneable
    {
        public Person Clone()
        {
            Console.WriteLine("this is Clone");
            return new Person();
        }
    }

显然,这是错的!虽然这是错的,但这就是返回类型的协变性,只是非泛型接口和方法重载不支持这一特性.

如果一定要这样写,只能使用显示接口实现:

    class Person : ICloneable
    {
        object ICloneable.Clone()
        {
            Console.WriteLine("this is ICloneable.Clone");
            return Clone();
        }

        public Person Clone()
        {
            Console.WriteLine("this is Clone");
            return new Person();
        }
    }

 

如果定义的是 ICloneable类型, 则调用上面的方法;

如果定义的是 Person 类型,则调用下面的方法;

            ICloneable ic = new Person();
            ic.Clone();
            Person p = new Person();
            p.Clone();

 

 

逆变:基类=>派生类

假设我们有这样一个类:

    class Person
    {
        public virtual void Process(Person person)
        {
            Console.WriteLine("this param is person");
        }
    }

我们想在派生类中写如下一个方法:

    class Student : Person
    {
        public override void Process(object o)
        {
            Console.WriteLine("this param is obj");
        }
    }

看起来很合理, 因为 object 是基类,肯定可以接受 Person 类的实例呀,这称为参数类型的逆变性

但实际上,和协变一样,非泛型接口接口和方法不支持

 

委托返回类型的协变性:

一个返回值为 基类 的委托变量,可以接收一个返回值为 派生类 的委托实例

 

    class Program
    {

        public delegate Parent DelgParent();
        public delegate Child DelgChild();

        static void Main(string[] args)
        {
            DelgParent del1 = Method1;
            DelgChild del2 = Method2;

            del1 = Method2;
            //del2 = Method1;//异常,返回类型错误

            Console.ReadKey();
        }

        public static Parent Method1() { return null; }

        public static Child Method2() { return null; }
    }

    class Parent { }

    class Child : Parent { }

 

 

委托参数的逆变性:

一个参数为 派生类 的委托变量, 可以接收一个参数为 基类 的委托实例

    class Program
    {
        delegate void PersonDelegate(Student s);
        static void Main(string[] args)
        {
            PersonDelegate pd = Test;
            pd(new Student());

            Console.ReadKey();
        }

        static void Test(Person p)
        {
            Console.WriteLine("person");
        }
    }

 

posted @ 2018-03-16 20:21  热敷哥  阅读(150)  评论(0编辑  收藏  举报