博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【转】c#中泛型的协变与逆变:<in T>详解
阅读量:4974 次
发布时间:2019-06-12

本文共 2971 字,大约阅读时间需要 9 分钟。

 

MSDN上的demo:

 

in(泛型修饰符)(C# 参考)

 
Visual Studio 2013
 
其他版本
 
0(共 1)对本文的评价是有帮助 
 

对于泛型类型参数,in 关键字指定该类型参数是逆变的。 可以在泛型接口和委托中使用 in 关键字。

通过逆变,可以使用与泛型参数指定的派生类型相比,派生程度更小的类型。 这样可以对委托类型和实现变体接口的类进行隐式转换。 引用类型支持泛型类型参数中的协变和逆变,但值类型不支持。

在泛型接口或委托中,如果类型形参仅用作方法返回类型,而不用于方法实参,则可声明为协变的。 Ref 和 out 参数不能为变体。

如果接口具有逆变类型形参,则允许其方法接受与接口类型形参指定的派生类型相比,派生程度更小的类型的实参。 例如,由于在 .NET Framework 4 的  接口中,类型 T 是逆变的,因此如果 Employee 继承 Person,则无需使用任何特殊转换方法,就可以将 IComparer(Of Person) 类型的对象指派给 IComparer(Of Employee) 类型的对象。

可以向逆变委托分配同一类型的其他委托,但需使用派生程度较小的泛型类型参数。

有关更多信息,请参见。

 

 

下例演示如何声明、扩展和实现一个逆变泛型接口。 此外还演示了如何对实现此接口的类使用隐式转换。

下例演示如何声明、实例化和调用一个逆变泛型委托。 此外还演示了如何隐式转换委托类型。

 
// Contravariant delegate.public delegate void DContravariant
(A argument);// Methods that match the delegate signature.public static void SampleControl(Control control){ }public static void SampleButton(Button button){ }public void Test(){ // Instantiating the delegates with the methods. DContravariant
dControl = SampleControl; DContravariant
具体要看维基百科的解释:

 

还是维基给力,摘录其中一段:

 

首先考虑数组类型构造器: 从Animal类型,可以得到Animal[](“animal数组”)。 是否可以把它当作

  • 协变:一个Cat[]也是一个Animal[]
  • 逆变:一个Animal[]也是一个Cat[]
  • 以上二者均不是(不变)?

如果要避免类型错误,且数组支持对其元素的读、写操作,那么只有第3个选择是安全的。Animal[]并不是总能当作Cat[],因为当一个客户读取数组并期望得到一个Cat,但Animal[]中包含的可能是个Dog。所以逆变规则是不安全的。

反之,一个Cat[]也不能被当作一个Animal[]。因为总是可以把一个Dog放到Animal[]中。在协变数组,这就不能保证是安全的,因为背后的存储可以实际是Cat[]。因此协变规则也不是安全的—数组构造器应该是不变。注意,这仅是可写(mutable)数组的问题;对于不可写(只读)数组,协变规则是安全的。

这示例了一般现像。只读数据类型(源)是协变的;只写数据类型(汇/sink)是逆变的。可读可写类型应是“不变”的。

更深入了解,请看此文章,个人看了之后豁然开朗。

 

  1.  
    先不考虑类型,我们考虑数学意义上的整数。考虑整数之间的小于关系——≤。这里关系实际上就是一个方法,接受
    2个数,返回布尔值。
  2.  
     
  3.  
    现在我们考虑一下对于整数的投影,投影指的是一个函数,接受一个整数,返回另一个整数。比如 z → z + z 我们可以定义为D(
    double), z →
    0 - z定义为N
    for (negate), z → z * z,定义为S(square).
  4.  
     
  5.  
    问题就出来了,是不是所有的情况下, (x ≤ y) = (D(x) ≤ D(y))?事实上就是,如果x小于等于y,那么x的
    2倍也小于等于y的
    2倍。投影D保留了不等号的方向。
  6.  
     
  7.  
    对于N,很显然,
    1
    2 但是 -
    1 ≥ -
    2。即(x ≤ y) = (N(y) ≤ N(x)),投影N反转了不等号的方向。
  8.  
     
  9.  
    对于S, -
    1
    0, S(
    0) ≤ S(-
    1),但是
    1
    2, S(
    2)≥ S(
    1)。可见投影S即没保留不等号方向,也没反转不等号方向。
  10.  
     
  11.  
    投影D就是协变的,它保留了整数上的次序关系。投影N是逆变的,它反转了整数上的次序关系,投影S两者都不是,所以是不变的。
  12.  
     
  13.  
    所以这里很清楚,整数自身不是变体,小于关系也不是变体。投影才是协变或者逆变——接受一个整数生成一个新整数。

 

转载于:https://www.cnblogs.com/eugene-21/p/9782286.html

你可能感兴趣的文章
两个表格中数据不用是一一对应关系--来筛选不同数据,或者相同数据
查看>>
静态方法是否属于线程安全
查看>>
js05-DOM对象二
查看>>
mariadb BINLOG_FORMAT = STATEMENT 异常
查看>>
C#生成随机数
查看>>
Java回顾之多线程
查看>>
机电行业如何进行信息化建设
查看>>
9、总线
查看>>
2018 Multi-University Training Contest 10 - Count
查看>>
HDU6203 ping ping ping
查看>>
构建之法阅读笔记02
查看>>
Fireworks基本使用
查看>>
.net Tuple特性
查看>>
Java基础常见英语词汇
查看>>
nginx启动、关闭命令、重启nginx报错open() "/var/run/nginx/nginx.pid" failed
查看>>
BZOJ 3097 Hash Killer I
查看>>
UINavigationController的视图层理关系
查看>>
html阴影效果怎么做,css 内阴影怎么做
查看>>
BZOJ1026: [SCOI2009]windy数
查看>>
样板操作数
查看>>