为什么foreach在从ListView中删除项目时起作用而在ListBox中不起作用?

我开始学习C#,我对我发现的行为感到有点困惑。 我试着弄清楚,为什么在一种情况下代码工作而在另一种情况下不工作:

foreach (ListViewItem l in listView1.SelectedItems) l.Remove(); foreach (object l in listBox1.SelectedItems) listBox1.Items.Remove(l); 

第一个工作正常,没有错误,但第二个抛出exception与集合被更改的信息。

有人能解释一下吗?

PS。 在ListView的情况下,我正在调试代码和集合SelectedItems正在改变,但即使它运作良好。

当我读取.NET中的代码,更具体地说是ListBox.csListView.cs ,它们有两个不同的类来保存它们的SelectedItems集合。

ListBox.csSelectedObjectCollection ,它有以下成员:

 private ListBox owner; private bool stateDirty; private int lastVersion; private int count; 

ListView.cs具有SelectedListViewItemCollection ,它仅包含以下成员:

 private ListView owner; private int lastAccessedIndex = -1; 

因此,通过查看,我想我可以推断出ListBox的集合是一个适当的枚举器,可以跟踪列表中的任何更改和项目数。 另一方面, ListView似乎根本不关心它,只跟踪枚举器的当前索引并简单地前进。

所以ListBox抛出exception,因为它跟踪修改, ListView没有。

编辑ListBox.csSelectecObjectCollection的GetEnumerator方法如下所示:

 public IEnumerator GetEnumerator() { return InnerArray.GetEnumerator(SelectedObjectMask); } 

ListView.csSelectedListViewItemCollection的GetEnumerator方法如下所示:

 public IEnumerator GetEnumerator() { if (owner.VirtualMode) { throw new InvalidOperationException(SR.GetString(SR.ListViewCantAccessSelectedItemsCollectionWhenInVirtualMode)); } ListViewItem[] items = SelectedItemArray; if (items != null) { return items.GetEnumerator(); } else { return new ListViewItem[0].GetEnumerator(); } } 

所以看起来ListView返回一个数组的枚举器,它是常量,而ListBox返回一个实际的枚举器作为其InnerArray项的filter。

我知道这不是你所问的; 但是在循环删除之前将所有项添加到临时列表总是有利的,因为你永远不知道枚举器是如何在后端实现的,也不知道它们将来如何改变。

 while (myListBox.SelectedItems.Count > 0) { myListBox.Items.Remove(myListBox.SelectedItems[0]); } 

您无法修改要枚举的集合。 这就是你在第二个例子中得到exception的原因。

ListView项上的Remove方法旨在在这种情况下不抛出exception。