zoukankan      html  css  js  c++  java
  • 协变和逆变

    协变:派生类=>基类

    假设有这样一个类:

        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");
            }
        }
  • 相关阅读:
    Java 常见异常种类
    Spring3.2+mybatis3.2+Struts2.3整合配置文件大全
    Java中的基本类型和引用类型变量的区别
    【git】Git 提示fatal: remote origin already exists 错误解决办法
    【Java集合】Java中集合(List,Set,Map)
    POJ3322-经典的游戏搜索问题
    程序人生[流程图]
    不使用中间变量交换两个数
    做人要低调,别把自己太当回事
    【转】嵌套子控件设计时支持
  • 原文地址:https://www.cnblogs.com/refuge/p/8584894.html
Copyright © 2011-2022 走看看