List <T>是否在foreach中用C#创建垃圾

Chr*_*tts 4 c# generics performance garbage-collection

纠正我,如果我错了,但在做一个foreach时,IEnumerable<T>无论T是什么,都会产生垃圾.但我想知道你是否有一个List<T>T是实体.然后说像Entity2D这样的列表中有一个派生类.它是否必须为每个派生类创建一个新的枚举器?因此创造垃圾?

还有一个接口让我们说IEntity作为T创建垃圾?

Ree*_*sey 22

List<T>的GetEnumerator方法实际上非常有效.

循环遍历a的元素时List<T>,它调用GetEnumerator.反过来,这会生成一个内部struct,它包含对原始列表的引用,索引和版本ID,以跟踪列表中的更改.

但是,由于正在使用结构,它实际上并没有创建GC将要处理的"垃圾".


至于"为每个派生类创建一个新的枚举器" - .NET泛型的工作方式与C++模板不同.在.NET中,List<T>类(及其内部Enumerator<T>结构)定义一次,并且可用于任何T.使用时,需要特定类型的T的泛型类型,但这只是新创建类型的类型信息,一般都很小.这与C++模板不同,例如,使用的每种类型都是在编译时创建的,并且"内置"到可执行文件中.

在.NET中,可执行指定的定义List<T>,不List<int>,List<Entity2D>等等......

  • +1.它们也与Java的泛型不同,后者纯粹是编译时的特性(所有出现的类型`T`都被视为`对象`) (2认同)

Mic*_*tum 7

我想你可能会对这篇文章感兴趣,这篇文章解释了为什么List(T)不会创建"垃圾",而不是Collection(T):

现在,这里是棘手的部分.有传言说System.Collections.Generic中的许多类型在使用foreach时都不会分配枚举器.例如,List的GetEnumerator返回一个结构,它只位于堆栈上.如果你不相信我,请使用.NET Reflector寻找自己.为了向自己证明一个关于List的foreach不会导致任何堆分配,我将实体更改为List,执行完全相同的foreach循环,并运行探查器.没有调查员!

[...]

但是,上面肯定有一个警告.列表上的Foreach循环仍然可以生成垃圾.[将列表强制转换为IEnumerable]即使我们仍在对List执行foreach,但是当列表转换为接口时,必须将值类型枚举器装箱并放在堆上.