cuo*_*gle 144 .net c# covariance contravariance c#-4.0
IEnumerable<T>是共变体,但它不支持值类型,仅支持引用类型.以下简单代码编译成功:
IEnumerable<string> strList = new List<string>();
IEnumerable<object> objList = strList;
Run Code Online (Sandbox Code Playgroud)
但是从更改string到int将得到编译错误:
IEnumerable<int> intList = new List<int>();
IEnumerable<object> objList = intList;
Run Code Online (Sandbox Code Playgroud)
原因在MSDN中解释:
差异仅适用于参考类型; 如果为变量类型参数指定值类型,则该类型参数对于生成的构造类型是不变的.
我搜索过并发现有些问题提到的原因是值类型和引用类型之间的装箱.但它仍然不清楚我的想法为什么拳击是什么原因?
有人可以给出一个简单而详细的解释为什么协方差和逆变不支持值类型以及拳击如何影响这个?
Jon*_*eet 122
基本上,当CLR可以确保它不需要对值进行任何代表性更改时,适用方差.引用看起来都一样 - 所以你可以使用a IEnumerable<string>作为一个IEnumerable<object>没有任何表示的变化; 本机代码本身不需要知道你在使用这些值做什么,只要基础结构确保它肯定是有效的.
对于值类型,这不起作用 - 将a处理IEnumerable<int>为IEnumerable<object>,使用序列的代码必须知道是否执行装箱转换.
您可能希望阅读Eric Lippert 关于表示和身份的博客文章,以获取有关此主题的更多信息.
编辑:自己重读了Eric的博客文章,它至少与身份和表现一样多,尽管这两者是相互关联的.特别是:
这就是为什么接口和委托类型的协变和逆变转换要求所有变化类型参数都是引用类型的原因.为确保变体引用转换始终保持身份,所有涉及类型参数的转换也必须是保持身份的.确保类型参数上的所有非平凡转换都是保持身份的最简单方法是将它们限制为引用转换.
Mar*_*age 10
如果你考虑底层表示,也许更容易理解(即使这确实是一个实现细节).这是一个字符串集合:
IEnumerable<string> strings = new[] { "A", "B", "C" };
Run Code Online (Sandbox Code Playgroud)
您可以将其strings视为具有以下表示:
[0] : string reference -> "A" [1] : string reference -> "B" [2] : string reference -> "C"
它是三个元素的集合,每个元素都是对字符串的引用.您可以将其强制转换为对象集合:
IEnumerable<object> objects = (IEnumerable<object>) strings;
Run Code Online (Sandbox Code Playgroud)
基本上它是相同的表示,除了现在引用是对象引用:
[0] : object reference -> "A" [1] : object reference -> "B" [2] : object reference -> "C"
表示是一样的.引用只是区别对待; 您无法再访问该string.Length酒店,但仍可以致电酒店object.GetHashCode().将此与一组int进行比较:
IEnumerable<int> ints = new[] { 1, 2, 3 };
Run Code Online (Sandbox Code Playgroud)
[0] : int = 1 [1] : int = 2 [2] : int = 3
要将此转换IEnumerable<object>为数据必须通过装箱整数进行转换:
[0] : object reference -> 1 [1] : object reference -> 2 [2] : object reference -> 3
此转换需要的不仅仅是演员表.
我认为一切都始于LSP(Liskov Substitution Principle)的定义,其中包括:
如果q(x)是可证明关于类型T的对象x的属性,那么对于类型S的对象y,q(y)应该为真,其中S是T的子类型.
但是,值类型,例如int不能代用object在C#.证明非常简单:
int myInt = new int();
object obj1 = myInt ;
object obj2 = myInt ;
return ReferenceEquals(obj1, obj2);
Run Code Online (Sandbox Code Playgroud)
false即使我们为对象分配相同的 "引用",这也会返回.
| 归档时间: |
|
| 查看次数: |
8497 次 |
| 最近记录: |