繁体   English   中英

为什么编译器为“ yield”生成的枚举数不是结构?

[英]Why is the compiler-generated enumerator for “yield” not a struct?

IEnumerator / IEnumerable编译器生成的实现 (用于yield方法和getter)似乎是一个类,因此分配在堆上。 但是,其他.NET类型(例如List<T>专门返回struct枚举数,以避免不必要的内存分配。 C#In Depth帖子的快速概述中,我看不出为什么在此情况并非如此。

我想念什么吗?

Servy正确回答了您的问题-您在评论中回答了自己的问题:

我刚刚意识到,由于返回类型是一个接口,所以无论如何它都会被装箱,对吗?

对。 您的后续问题是:

方法不能更改为返回显式类型的枚举数(如List<T>一样)吗?

因此,您的想法是用户写:

IEnumerable<int> Blah() ...

然后,编译器实际上会生成一个返回BlahEnumerable的方法,该方法是实现IEnumerable<int> ,但具有适当的GetEnumerator等方法和属性,这些属性可以允许foreach的“模式匹配”功能取消装箱。

尽管这是一个合理的想法,但是当您开始说谎关于方法的返回类型时,会遇到很多困难。 特别是当谎言涉及更改方法是否返回结构或引用类型时。 考虑所有出错的地方:

  • 假设该方法是虚拟的。 如何覆盖它? 虚拟覆盖方法的返回类型必须与覆盖方法完全匹配。 (同样,对于:方法覆盖另一个方法,该方法实现接口的方法,依此类推。)

  • 假设该方法被制成委托Func<IEnumerable<int>> Func<T>T是协变的,但协变仅适用于引用类型的类型实参。 该代码看起来像返回了IEnumerable<T>但实际上它返回的值类型与IEnumerable<T>不协方差兼容,仅赋值兼容

  • 假设我们有一个void M<T>(T t) where T : class ,我们称之为M(Blah()) 我们期望推断出TIEnumerable<int> ,它通过了约束检查,但结构类型没有通过约束检查。

等等。 您很快就进入了Three's Company的一集中(男孩,我在这里与自己约会),其中一个小谎言最终加剧了巨大的灾难。 所有这些节省了少量的收集压力。 不值得。

我注意到,尽管编译器创建的实现确实以一种有趣的方式节省了收集压力。 一次在返回的枚举数上调用GetEnumerator ,该枚举数将自身转换为枚举数。 当然,第二次状态不同,因此它分配了一个新对象。 由于99.99%的可能性是给定序列仅被枚举一次,因此节省了很大的收集压力。

此类只能通过接口使用。 如果它是一个结构,它会被装箱的100%的时间,使得它比使用类效率较低

根据定义,您不能将其装箱,因为根据定义,它无法在编译时使用,因为在开始编译代码时该类型不存在

在编写IEnumerator的自定义实现时,可以在编译代码之前公开实际的基础类型,从而无需包装就可以潜在地使用它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM