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

Woj*_*lik 4 c# foreach listview listbox

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

foreach (ListViewItem l in listView1.SelectedItems) l.Remove();
foreach (object l in listBox1.SelectedItems) listBox1.Items.Remove(l);
Run Code Online (Sandbox Code Playgroud)

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

有谁可以向我解释一下?

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

Stm*_*ted 5

当我看到里面的.NET代码,更具体ListBox.csListView.cs,他们有保持他们的两个不同的类SelectedItems集合.

ListBox.csSelectedObjectCollection,有这些成员:

private ListBox owner;
private bool    stateDirty; 
private int     lastVersion; 
private int     count;
Run Code Online (Sandbox Code Playgroud)

ListView.csSelectedListViewItemCollection,只有这些成员:

private ListView owner;
private int lastAccessedIndex = -1;
Run Code Online (Sandbox Code Playgroud)

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

所以ListBox抛出异常,因为它跟踪修改,ListView但没有.

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

public IEnumerator GetEnumerator() {
    return InnerArray.GetEnumerator(SelectedObjectMask); 
}
Run Code Online (Sandbox Code Playgroud)

并且ListView.cs's SelectedListViewItemCollection的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(); 
    }
} 
Run Code Online (Sandbox Code Playgroud)

所以它看起来像ListView返回一个数组的枚举器,它是常量,同时ListBox返回一个实际的枚举器作为其InnerArray项的过滤器.

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