协变和逆变

二、真正的协变和逆变

概念:

1、以前的泛型系统(或者说没有in/out关键字时),是不能“变”的,无论是“逆”还是“顺(协)”。
2、当前仅支持接口和委托的逆变与协变 ,不支持类和方法。但数组也有协变性。
3、值类型不参与逆变与协变。

协变:Foo<ParentClass> = Foo<ChildClass>

public class TestOut<T> where T : new()
{
    /*
     * 关键字out因为协变的类型T只能作为输出参数使用,而不能作为输入参数
     */
    //*****[协变]泛型委托Demo*****
    //1、创建泛型委托
    public delegate T MyFunA<T>();     //默认不支持协变与逆变
    public delegate T MyFunB<out T>(); //设置支持协变
    //public delegate void MyFunC<out T>(T param);//错误,协变类型只能“出”不能“入”(只能作为输出的返回类型,不能作为输入的参数类型!)
    //2、创建委托变量
    public MyFunA<object> FunAObject = null;
    public MyFunA<string> FunAString = null;
    public MyFunB<object> FunBObject = null;
    public MyFunB<string> FunBString = null;
    public MyFunB<int> FunBInt = null;
    //3、验证结果
    public void TestFun()
    {
        //FunAObject = FunAString;//错误,不可用协变
        FunBObject = FunBString;//正确,可用协变可以完成子类string到父类object的转换
        //FunBObject = FunBInt;   //错误,值类型不参与协变
    }

    //*****[协变]泛型接口Demo*****
    //1、创建泛型接口
    public interface IMyInterfaceA<T> { }       //默认不支持协变与逆变
    public interface IMyInterfaceB<out T> { }   //设置支持协变
    //public interface IMyInterfaceC<out T>
    //{
    //    void Test(T param);//错误,协变只能“出”不能“入”
    //}
    //2、创建接口变量
    public IMyInterfaceA<object> interAObject = null;
    public IMyInterfaceA<string> interAString = null;
    public IMyInterfaceB<object> interBObject = null;
    public IMyInterfaceB<string> interBString = null;
    public IMyInterfaceB<int> interBInt = null;
    //3、验证结果
    public void TestInterface()
    {
        //interAObject = interAString;    //错误,不可用协变
        interBObject = interBString;    //正确,可用协变可以完成子类string到父类object的转换
        //interBObject = interBInt;       //错误,值类型不参与协变
    }
}

 

逆变:Foo<ChildClass> = Foo<ParentClass>

public class TestIn<T> where T : new()
{
    /*
     * 关键字in因为逆变的类型只能作为输入参数,而不能作为输出参数
     */
    //*****[逆变]泛型委托*****
    //1、创建泛型委托
    public delegate void MyActionA<T>(T param);     //默认不支持协变与逆变
    public delegate void MyActionB<in T>(T param);  //设置支持逆变
    //public delegate T MyActionC<in T>();//错误,逆变只能“入”不能“出”(只能作为输入的参数类型,不能作为输出的返回类型!)    //2、创建委托变量
    public MyActionA<object> ActionAObject = null;
    public MyActionA<string> ActionAString = null;
    public MyActionB<object> ActionBObject = null;
    public MyActionB<string> ActionBString = null;
    public MyActionB<int> ActionBInt = null;
    //3、验证结果
    public void TestAction()
    {
        //ActionAString = ActionAObject;  //错误,不可用逆变
        ActionBString = ActionBObject;  //正确,可用逆变可以完成从父类object到子类string的转换
        //ActionBInt = ActionBObject;     //错误,值类型不参与逆变
    }

    //*****[逆变]泛型接口*****
    //1、创建泛型接口
    public interface IMyInterfaceA<T> { }     //默认不支持协变与逆变
    public interface IMyInterfaceB<in T> { }  //设置支持逆变
    //public interface IMyInterfaceC<in T>
    //{
    //    T Test();//错误,逆变只能“入”不能“出”
    //}
    //2、创建接口变量
    public IMyInterfaceA<object> interAObject = null;
    public IMyInterfaceA<string> interAString = null;
    public IMyInterfaceB<object> interBObject = null;
    public IMyInterfaceB<string> interBString = null;
    public IMyInterfaceB<int> interBInt = null;
    //3、验证结果
    public void TestInterface()
    {
        //interAString = interAObject;    //错误,不可用逆变
        interBString = interBObject;    //正确,可用你变可以完成从父类object到子类string的转换
        //interBInt = interBObject;       //错误,值类型不参与逆变
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值