[英]C# preventing Collection Was Modified exception
是否
foreach(T value in new List<T>(oldList) )
當oldList包含1百萬個對象T時危險(代價高昂)?
更常見的是,在枚舉期間添加/刪除元素時,枚舉oldList的最佳方法是什么?
一般規則是,您不應修改您枚舉的同一集合。 如果你想做類似的事情,請保留另一個集合,該集合將跟蹤從原始集合中添加/刪除的元素,然后在退出循環后,對原始集合執行添加/刪除操作。
像這樣
var itemsToBeRemoved = new List<T>();
foreach (T item in myHugeList)
{
if (/*<condition>*/)
itemsToBeRemoved.Add(item);
}
myHugeList.RemoveRange(itemsToBeRemoved);
我通常只為要刪除或添加的所有對象創建一個列表。
在foreach
我只是將項添加到相應的集合中,並在foreach
完成后修改原始集合(循環遍歷removeItems
和addItems
集合)
如果您使用Foreach循環來修改集合,那么您將收到如下錯誤。
List<string> li = new List<string>();
li.Add("bhanu");
li.Add("test");
foreach (string s in li)
{
li.Remove(s);
}
解決方案 - 使用For Loop,如下所示。
for (int i = 0; i < li.Count; i++)
{
li.RemoveAt(i);
i--;
}
如果你的意思是你可以從另一個線程添加/刪除對象,我會:1 - 在添加/刪除線程中同步線程2-,創建要添加或刪除的項目列表3-然后在關鍵項中刪除這些項目部分(所以它很小 - 將項目添加到刪除列表時不必同步)
如果你不想這樣做,你可以使用for而不是foreach,這樣可以避免異常,但你必須格外小心,這樣你就不會得到其他類型的異常
foreach(新列表中的T值(oldList).ToList()) - 試一試
您可以使用標志將修改切換到臨時列表,同時枚舉原始列表。
///你在哪里枚舉
isBeingEnumerated = true
foreach(T value in new List<T>(oldList) )
isBeingEnumerated = false
SyncList(oldList with temporaryList)
///在枚舉時修改的位置
if isBeingEnumerated then
use a temporaryList to make the changes.
它會“慢”但除了在后台線程上運行之外,你無法做更多的事情。 例如,使用BackgroundWorker 。
如果列表上的操作僅發生在一個線程上,則正確的方法是添加要添加/刪除的項目以分隔列表,並在迭代完成后執行這些操作。
如果你使用多個線程,你將不得不研究多線程編程,例如使用鎖或者更好的ReaderWriterLock 。
更新:正如另一個Stack Overflow問題中所提到的,現在可以在使用並發集合時在.NET 4.0 中輕松實現 。
您可以在不使用枚舉器的情況下遍歷列表,所以請執行以下操作:
for(int i = 0;i<oldList.Count;i++) {
var value = oldList[i];
...
if(itemRemoveCondition) {
oldList.RemoveAt(i--);
}
}
對我來說,首先應該考慮使用某種數據分頁,因為擁有這樣的1百萬項大型列表本身就很危險。
你聽說過工作單元模式嗎?
您可以實現它,以便標記對象以進行創建,更新或刪除,之后,您可以調用“SaveChanges”,“Commit”或任何其他執行“應用更改”的工作,您將完成。
例如,您遍歷可枚舉(oldList)並將其標記為“delete”。 稍后,您調用“SaveChanges”,更抽象,通用的工作單元將遍歷要處理的小的,已過濾的對象列表。
無論如何,避免列出百萬件物品。 您應該使用分頁的對象列表。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.