zoukankan      html  css  js  c++  java
  • 接口的实现方式(显示和隐示)及协变和逆变

    接口的实现方式(显示和隐示)及协变和逆变

    如果一个类继承了两个不同的接口,且这两个接口有一样的成员,类实例任意调用I1,I2接口:
    如:

    public interface I1
    {
        string GetSome();
    }
    
    public interface I2
    {
        string GetSome();
    }
    public class MyClass : I1, I2
    {
        public string GetSome()
        {
            return "Some";
        }
    }
    
    MyClass c1 = new MyClass();
    
        I1 i1 = (I1) c1;
        I2 i2 = (I2) c1;
    
        c1.GetSome();
        i1.GetSome();
        i2.GetSome();
    

    但是通常不同接口即使成员名称相同,返回值相同,实现的目的功能还是不一样的。所以区分接口还是非常必须要的。那么如何在类里区分继承了两个有相同约束的接口呢?

    接口显示实现

    显示实现I1接口(接口名称.成员)

    public class MyClass : I1, I2
    {
        public string GetSome()
        {
            return "Some";
        }
        //接口成员的访问修饰符默认为public,且不能显示实现和修改,同样显示实现接口的类的成员也不可以有访问修饰符。
        string I1.GetSome()
        {
            return "I1.Some";
        }
    }
    

    这时i1.GetSome()的输出就是"I1.Some",i2.GetSome()和c1.GetSome()不变为"Some"


    只显示继承I1接口,不实现I2接口

    public class MyClass : I1, I2
    {   
        string I1.GetSome()
        {
            return "I1.Some";
        }
    }
    

    编译报错,因为没有实现接口I2。所以即使I1,I2有相同的约束,显示实现是区分I1和I2的。隐示实现的话不区分I1,I2,可以只写一个方法。


    只显示实现I1接口

    public class MyClass : I1
    {   
        string I1.GetSome()
        {
            return "I1.Some";
        }
    }
    

    只显示实现接口I1,必须用接口来调用,不可以使用类实例来访问GetSome()方法

    //错误
    MyClass my1=new MyClass();
    my.GetSome();
    //正确
    I1 i1=(I1) my1;
    i1.GetSome();
    //正确
    I1 i1=new MyClass();
    i1.GetSome();
    

    所以当类实现多个有冲突的成员的接口时,显示使用接口可以解决这些冲突的接口成员。


    泛型接口的协变和逆变

    两个有继承关系的类

    public class Parent { }
    public class Child : Parent { }
    

    类相互间转换

    Parent parent=new Child();//正常转换
    Child child=new Parent();//禁止转换
    Child child=(Child)new Parent();//禁止强制转换
    
    Parent[] arrParent = new Child[] {};//正常转换
    

    子类可以安全的转换为父类,反之则不行。同理数组间的转换也遵循这个原则。

    所以一个子类到父类的可变性称之为协变,反之为逆变。具体在泛型接口上体现为参数的in,out关键字的使用。
    例如:IEnumerable泛型的实现是IEnumerable<out T>,List泛型实现是List<T>。前者可以实现协变,后者不可以。所以只有添加了out关键字的泛型接口才可以实现协变(子类转换为父类)。

    泛型接口参数没有关键字

    public interface TI<T>{}
    public class ParentCollection : TI<Parent>{}
    public class ChildCollection : TI<Child>{}
    
    TI<Parent> Parents = new ChildCollection();//编译错误
    TI<Child> Childs = new ParentCollection();//编译错误
    

    如果泛型接口的参数没有使用in,out关键字,那么不管是协变还是逆变都是不能实现的。


    泛型接口参数带有out关键字

    public interface TI<out T>
    {
        T Get();
    }
    public class ParentCollection : TI<Parent>
    {
        public Parent Get()
        {
            return new Parent();
        }
    }
    public class ChildCollection : TI<Child>
    {
        public Child Get()
        {
            return new Child();
        }
    }  
    

    调用实现out参数接口的类

    TI<Parent> Parents = new ChildCollection();//协变转换
    TI<Child> Childs = new ParentCollection();//编译错误,无法转换
    

    总结:实现out关键字参数的接口可以实现协变(子类转换为父类)。

    泛型参数接口带有in关键字

    public interface TI<in T>
    {
        void Method(T param);
    }
    public class ParentCollection : TI<Parent>
    {
        public void Method(Parent p){}
    }
    
    public class ChildCollection : TI<Child>
    {
        public void Method(Child c){}
    }
    

    调用实现in参数接口的类

    TI<Parent> Parents = new ChildCollection();//编译错误
    TI<Child> Childs = new ParentCollection();//逆变转换
    

    总结:带有in参数接口的类可以实现逆变转换(父类转换为子类)

    对比发现实现in,out参数接口的方法是不一样的。

    //协变
    public interface TI<out T>
    {
        T Get();
        void Method(T param);//编译错误,只能定义在逆变的接口
    }
    //逆变
    public interface TI<in T>
    {
        T Get();//编译错误,只能定义在协变的接口
        void Method(T param);
    }
    

    总结:协变的泛型类型只能作为输出类型,不能作为输入类型(out关键字只能影响输出类型),逆变的泛型类型只能作为输入类型,不能作为输出类型(in关键字只能影响输入类型)

  • 相关阅读:
    HTTP Error 500.19
    为了找到自己的路——leo锦书62
    hdu3068 最长回文串
    AE+SceneControl源代码共享
    从节能的数据中心的硬件和软件设计的角度(一)
    设计模式------工厂方法模式
    PSU 离11.2.0.3.0 -&gt; 11.2.0.3.11 如果解决冲突的整个
    Android四个多线程分析:MessageQueue实现
    shiro权限架作战
    Codeforces 549G. Happy Line 馋
  • 原文地址:https://www.cnblogs.com/JoeSnail/p/6274143.html
Copyright © 2011-2022 走看看