当它可以被修改时经历一个foreach?

我想在取出foreach循环的成员时执行foreach循环,但这会抛出错误。 我唯一的想法是在这个循环中创建另一个列表以找到要删除的切片,并循环遍历新列表以从Pizza中删除项目。

foreach(var Slice in Pizza) { if(Slice.Flavor == "Sausage") { Me.Eat(Slice); //This removes an item from the list: "Pizza" } } 

你可以做到这一点,到目前为止我发现的最简单的方法(想想我发明了它,确定这不是真的;))

 foreach (var Slice in Pizza.ToArray()) { if (Slice.Flavor == "Sausage") // each to their own.. would have gone for BBQ { Me.Eat(Slice); } } 

因为它正在迭代循环的固定副本。 它将迭代所有项目,即使它们被删除。

得心应手不是!

(顺便说一句,这是一种迭代集合副本的方便方法,具有线程安全性,并删除对象被锁定的时间:锁定,获取ToArray()副本,释放锁定,然后迭代)

希望有所帮助!

如果您必须遍历列表并需要删除项目,请使用for循环向后迭代:

 // taken from Preet Sangha's answer and modified for(int i = Pizza.Count-1; i >= 0, i--) { var Slice = Pizza[i]; if(Slice.Flavor == "Sausage") { Me.Eat(Slice); //This removes an item from the list: "Pizza" } } 

向后迭代的原因是当你删除Elements时,你不会遇到因在我们删除了第六个元素的Pizza上访问Pizza [5]而导致的IndexOutOfRangeException。

使用for循环的原因是因为迭代器变量i与Pizza无关,所以你可以在没有枚举器“破坏”的情况下修改Pizza

使用for循环而不是foreach

 for(int i = 0; i < in Pizza.Count(), ++i) { var Slice = Pizza[i]; if(Slice.Flavor == "Sausage") { Me.Eat(Slice); //This removes an item from the list: "Pizza" } } 

接近这个的最明确的方法是建立一个吃片的列表,然后处理它,避免在循环中改变原始枚举。 我从来不喜欢使用索引循环,因为它可能容易出错。

 List slicesToEat=new List(); foreach(var Slice in Pizza) { if(Slice.Flavor == "Sausage") { slicesToEat.Add(Slice); } } foreach(var slice in slicesToEat) { Me.Eat(slice); } 

也许更改你的Me.Eat()签名以获取IEnumerable

 Me.Eat(Pizza.Where(s=>s.Flavor=="Sausage").ToList()); 

这使您可以在一行代码中执行任务。

然后你的Eat()就像:

 public void Eat(IEnumerable remove) { foreach (Slice r in remove) { Pizza.Remove(r); } } 

VB6样式的“Collection”对象允许在枚举期间进行修改,并且在发生此类修改时似乎能够合理地工作。 太糟糕了它有其他限制(键类型仅限于不区分大小写的字符串)并且不支持generics,因为其他集合类型都不允许修改。

坦率地说,我不清楚为什么微软的iEnumerable合同要求在修改集合时抛出exception。 我理解一个要求,如果对集合的更改使得枚举无法继续而没有古怪(跳过或复制枚举,崩溃等期间未更改的值),则会抛出exception但是没有理由不这样做允许一个可以合理列举的集合。

你在哪里可以订购披萨,其中切片有独立的浇头? 无论如何…

使用Linq:

 // Was "Me.Eat()" supposed to be "this.Eat()"? Pizza .Where(slice => slice.Flavor == "Sausage") .Foreach(sausageSlice => { Me.Eat(sausageSlice); }); 

前两行创建一个仅包含香肠切片的新列表。 第三个将采用该新子集并将每个切片传递给Me.Eat()。 {和;}可能是多余的。 这不是最有效的方法,因为它首先制作副本(与已经给出的许多其他方法一样),但它肯定是干净和可读的。

顺便说一句,这只适用于后人,因为已经给出了最好的答案 – 按索引向后迭代。

比萨什么样的系列? 如果它是List ,那么您可以调用RemoveAll方法:

 Pizza.RemoveAll(slice => string.Equals(slice.Flavor, "Sausage"));