这个foreach循环会产生垃圾吗?

4

我发现了一种通过将列表转换为自身来更改foreach循环中的列表的方法,如下所示:

foreach (var item in myList.ToList())
{
     //add or remove items from myList
}

如果你试图直接修改myList,会抛出错误,因为枚举器基本上会将其锁定。
这个方法之所以能行,是因为它并没有修改原始的myList。我的问题是,当循环结束时,这种方法是否会创建garbage(即从ToList方法返回的List)? 对于小循环来说,使用for loop来避免创建垃圾是否更可取?

2
这个推理不是反过来了吗,至少给出了“//从myList添加或删除项目”的评论?难道不应该写成(有点长):“这能够工作是因为不是myList迭代(而是使用ToList()创建的副本),所以可以在foreach循环中修改myList。” - Christian.K
5个回答

5
第二个列表将是垃圾,其中将包含用于构建第二个列表的枚举器的垃圾,并添加foreach生成的枚举器,无论是否使用第二个列表都会出现。
如果您可以指出此代码区域是真正的性能瓶颈,那么您应该切换到for。否则,请为简单性和可维护性编写代码。

3
是的。ToList()会创建另一个列表,需要进行垃圾回收。

1

这是一个有趣的技巧,我会记在心里以备将来之需!(我简直不敢相信我从未想过!)

无论如何,是的,您正在构建的列表不会自动取消分配。使用此技术可能存在的性能问题包括:

  1. 增加内存使用量(构建一个与 IEnumerable 分开的 List)。除非您经常这样做或 IEnumerable 非常大,否则可能并不是很大的问题。
  2. 速度降低,因为它必须一次通过 IEnumerable 来构建 List
  3. 此外,如果枚举 IEnumerable 具有副作用,则此过程将触发所有副作用。

除非实际上是在内部循环中,或者您正在处理非常大的数据集,否则您可能可以毫无问题地执行此操作。


1

是的,ToList() 方法会创建“垃圾”。我会选择使用索引。

for (int i = MyList.Count - 1; 0 <= i; --i)
{
    var item = MyList[i];
    //add or remove items from myList
}

在证明原始代码是瓶颈之前,我会暂缓进行此优化。如果不是瓶颈,那么使代码难以阅读就没有意义了。 - Harry Steinhilber

0

这是非确定性的。但从调用 ToList() 创建的引用最终将被垃圾回收。

我不会太担心它,因为它最多只会持有引用或小值类型。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接