1768人阅读 评论(0)

# 协变和抗变

## 一.定义

    public class Sharp
{
}

public class Rectange : Sharp
{
}

Sharp sharp = new Rectange();

Sharp[] sharps=new Rectange[3];

Rectange[] rectanges = new Sharp[3];

            Sharp sharp = new Rectange();

            IEnumerable<Sharp> sharps = new List<Rectange>();
4.0之后，可以允许按上面的写法了，因为泛型接口IEnumerable<T>被声明成如下：
public interface IEnumerable<out T> : IEnumerable

## 二.泛型接口中的协变和抗变

public interface ICovariant<T>
{
}


    public class Sharp : ICovariant<Sharp>
{
}

public class Rectange : Sharp,ICovariant<Rectange>
{
}

        static void Main(string[] args)
{
ICovariant<Sharp> isharp = new Sharp();
ICovariant<Rectange> irect = new Rectange();

isharp = irect;
}

    public interface ICovariant<out T>
{
}

        static void Main(string[] args)
{
ICovariant<Sharp> isharp = new Sharp();
ICovariant<Rectange> irect = new Rectange();

irect = isharp;
// isharp =irect;
}

ICovariant<Sharp>

ICovariant<Rectange>

    public interface ICovariant<in T>
{
}

    //这时候，无论如何修饰T，都不能编译通过
public interface ICovariant<out T>
{
T Method1();
void Method2(T param);
}

1）当我用out修饰时，即允许接口对类型参数T协变，也就是满足从ICovariant<Rectange>到ICovariant<Sharp>转换，Method1返回值Rectange到Sharp转换没有任何问题：
            ICovariant<Sharp> isharp = new Sharp();
ICovariant<Rectange> irect = new Rectange();

isharp = irect;
Sharp sharp = isharp.Method1();

            ICovariant<Sharp> isharp = new Sharp();
ICovariant<Rectange> irect = new Rectange();

isharp = irect;
isharp.Method2(new Sharp());

Method2(Rectange)

2)同样，当我用in修饰时，

            ICovariant<Sharp> isharp = new Sharp();
ICovariant<Rectange> irect = new Rectange();

//isharp = irect;
irect = isharp;
irect.Method2(new Rectange());
Method2(Sharp)会去替换Method2(Rectange)，所以上面的最后一句代码无论以Rectange类型还是Sharp类型为参数都没有任何问题；

            ICovariant<Sharp> isharp = new Sharp();
ICovariant<Rectange> irect = new Rectange();

//isharp = irect;
irect = isharp;
Rectange rect = irect.Method1();

    public interface ICovariant<out T>
{
T Method1();

}

public interface IContravariant<in T>
{
void Method2(T param);
}

.net中很多接口都仅将参数用于函数返回类型或函数参数类型，如：
public interface IComparable<in T>
public interface IEnumerable<out T> : IEnumerable

1.仅有泛型接口和泛型委托支持对类型参数的可变性，泛型类或泛型方法是不支持的。
2.值类型不参与协变或抗变，IFoo<int>永远无法协变成IFoo<object>，不管有无声明out。因为.NET泛型，每个值类型会生成专属的封闭构造类型，与引用类型版本不兼容。
3.声明属性时要注意，可读写的属性会将类型同时用于参数和返回值。因此只有只读属性才允许使用out类型参数，只写属性能够使用in参数。

    public interface ICovariant<out T>
{
T Method1();
void Method3(IContravariant<T> param);
}

public interface IContravariant<in T>
{
void Method2(T param);
}

    public interface IContravariant<in T>
{

}
public interface ICovariant<out T>
{

}

public interface ITest<out T1, in T2>
{
ICovariant<T1> test1();
IContravariant<T2> test2();
}

## 三.泛型委托中的协变和抗变

        public delegate void MyDelegate1<T>();

            MyDelegate1<Sharp> sharp1 = new MyDelegate1<Sharp>(MethodForParent1);
MyDelegate1<Rectange> rect1 = new MyDelegate1<Rectange>(MethodForChild1);
sharp1 = rect1;

        public static void MethodForParent1()
{
Console.WriteLine("Test1");
}
public static void MethodForChild1()
{
Console.WriteLine("Test2");
}

        public delegate void MyDelegate1<out T>();

            MyDelegate1<Sharp> sharp1 = new MyDelegate1<Sharp>(MethodForParent1);
MyDelegate1<Rectange> rect1 = new MyDelegate1<Rectange>(MethodForChild1);
//sharp1 = rect1;
rect1 = sharp1;

        public delegate void MyDelegate1<in T>();

        public delegate T MyDelegate2<out T>();


            MyDelegate2<Sharp> sharp2 = new MyDelegate2<Sharp>(MethodForParent2);
MyDelegate2<Rectange> rect2 = new MyDelegate2<Rectange>(MethodForChild2);
sharp2 = rect2;

        public static Sharp MethodForParent2()
{
return new Sharp();
}
public static Rectange MethodForChild2()
{
return new Rectange();
}

        public delegate T MyDelegate2<in T>();
            MyDelegate2<Sharp> sharp2 = new MyDelegate2<Sharp>(MethodForParent2);
MyDelegate2<Rectange> rect2 = new MyDelegate2<Rectange>(MethodForChild2);
//sharp2 = rect2;
rect2 = sharp2;

            Rectange rectange = rect2();


        public delegate Contra<T> MyDelegate2<in T>();
public delegate void Contra<in T>();

        public static Contra<Sharp> MethodForParent3()
{
return new Contra<Sharp>(MethodForParent1);
}
public static Contra<Rectange> MethodForChild3()
{
return new Contra<Rectange>(MethodForChild1);
}

            MyDelegate2<Sharp> sharp2 = new MyDelegate2<Sharp>(MethodForParent3);
MyDelegate2<Rectange> rect2 = new MyDelegate2<Rectange>(MethodForChild3);
rect2 = sharp2;

        public delegate T MyDelegate3<T>(T param);

        public delegate T MyDelegate3<out T>(T param);

        public static Sharp MethodForParent4(Sharp param)
{
return new Sharp();
}
public static Rectange MethodForChild4(Rectange param)
{
return new Rectange();
}
            MyDelegate3<Sharp> sharp3 = new MyDelegate3<Sharp>(MethodForParent4);
MyDelegate3<Rectange> rect3 = new MyDelegate3<Rectange>(MethodForChild4);
sharp3 = rect3;

        public delegate T MyDelegate3<out T>(Contra<T> param);

        public static Sharp MethodForParent4(Contra<Sharp> param)
{
return new Sharp();
}
public static Rectange MethodForChild4(Contra<Rectange> param)
{
return new Rectange();
}

        public delegate Contra<T> MyDelegate3<in T>(T param);

        public static Contra<Sharp> MethodForParent4(Sharp param)
{
return new Contra<Sharp>(MethodForParent1);
}
public static Contra<Rectange> MethodForChild4(Rectange param)
{
return new Contra<Rectange>(MethodForChild1);
}

        public delegate T1 MyDelegate4<T1,T2,T3>(T2 param1,T3 param2);

        public delegate T1 MyDelegate4<out T1,in T2,in T3>(T2 param1,T3 param2);

        public delegate T1 MyDelegate4<in T1,out T2,in T3>(T2 param1,T3 param2);

1）方法返回类型的协变-抗变一致原则；
2）方法参数类型的协变-抗变互换原则！

        public delegate Contra<T1> MyDelegate4<in T1, out T2, in T3>(Contra<T2> param1, T3 param2);

0
0

【直播】机器学习&数据挖掘7周实训--韦玮
【套餐】系统集成项目管理工程师顺利通关--徐朋
【直播】3小时掌握Docker最佳实战-徐西宁
【套餐】机器学习系列套餐（算法+实战）--唐宇迪
【直播】计算机视觉原理及实战--屈教授
【套餐】微信订阅号+服务号Java版 v2.0--翟东平
【直播】机器学习之矩阵--黄博士
【套餐】微信订阅号+服务号Java版 v2.0--翟东平
【直播】机器学习之凸优化--马博士
【套餐】Javascript 设计模式实战--曾亮

* 以上用户言论只代表其个人观点，不代表CSDN网站的观点或立场
个人资料
• 访问：68426次
• 积分：1091
• 等级：
• 排名：千里之外
• 原创：38篇
• 转载：0篇
• 译文：0篇
• 评论：12条
评论排行
最新评论