dictionary in while loop and removing items in dictionary
我有一个字典,如果字典中的项目通过所有的处理,我想删除它。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | var dictEnum = dictObj.GetEnumerator(); while (dictEnum.MoveNext()) { Parallel.ForEach(dictObj, pOpt, (KVP, loopState) => { processAndRemove(KVP.Key); }); } private void processAndRemove(string keyId) { try { <does stuff> dictObj.Remove(keyId); } catch(exception ex) { ... <does not remove anything, wants to retry until it doesn't fail> } } |
我希望循环继续处理字典中的所有剩余项(未删除)。
但是,我得到了一个错误。当我运行此代码的更简单版本时,会收到一条消息,说明:
Collection was modified; enumeration operation may not execute
号
有没有办法用字典来做这个?
更新:
只是为了提供更多的上下文。这背后的想法是,如果dictobj中还有项目,那么循环将继续运行。所以如果我从10和8开始,我想重新运行2,直到他们通过。
正如Jalayn所说,在枚举集合时不能将其从集合中移除。您必须重写代码,以便它添加到另一个集合中,然后枚举该集合并从原始集合中删除这些项。
比如:
1 2 3 4 5 6 7 8 9 10 11 | var toRemove = new Dictionary<int, string>() //whatever type it is Parallel.ForEach(dictObj, pOpt, (KVP, loopState) => { toRemove.Add(KVP); }); foreach (var item in toRemove) { dictObject.Remove(item.Key); } |
号
如果同时对某个集合进行迭代,则无法从该集合中移除该项。但是,您可以将要删除的所有元素存储在单独的集合中。
然后,枚举完之后,可以遍历列表以从原始集合中删除每个项。
或者,检查从C字典中删除与谓词匹配的多个项的最佳方法?很漂亮。由@jaredpar用户提供的公认答案摘录是:
1 2 3 | foreach ( var s in MyCollection.Where(p => p.Value.Member == foo).ToList() ) { MyCollection.Remove(s.Key); } |
从我和杰佩·斯蒂格·尼尔森的谈话中,我产生了一个想法,想试试埃多克斯1号(8号)。
这是我的测试代码,我可以从字典中删除项目(在parallel.foreach循环中),并且
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | public static ConcurrentDictionary<string, myRule> ccDict= new ConcurrentDictionary<string, myRule>(); try { while (ccDict.Count > 0) { Parallel.ForEach(ccDict, pOptions, (KVP, loopState) => { //This is the flag that tells the loop do exit out of loop if a cancellation has been requested pOptions.CancellationToken.ThrowIfCancellationRequested(); processRule(KVP.Key, KVP.Value, loopState); }); //End of Parallel.ForEach loop } } catch (Exception ex) { Console.WriteLine(ex.Message.ToString()); Console.ReadLine(); } public static int processRule(string rId, myRule rule, ParallelLoopState loopState) { try { if (rId =="001" || rId =="002") { if (rId =="001" && ccDict[rId].RetryAttempts == 2) { operationPassed(rId); return 0; } operationFailed(rId); } else { operationPassed(rId); } return 0; } catch (Exception ex) { Console.WriteLine("failed :" + ex.Message.ToString()); return -99; } } private static void operationPassed(string rId) { //Normal Operation ccDict[rId].RulePassed = true; ccDict[rId].ExceptionMessage =""; ccDict[rId].ReturnCode = 0; Console.WriteLine("passed:" + rId +" Retry Attempts :" + ccDict[rId].RetryAttempts.ToString()); rule value; ccDict.TryRemove(rId, out value); } private static void operationFailed(string ruleId) { //This acts as if an EXCEPTION has OCCURED int retryCount = 0; ccDict[rId].RulePassed = false; ccDict[rId].RetryAttempts = ccDict[rId].RetryAttempts + 1; ccDict[rId].ExceptionMessage ="Forced Fail"; ccDict[rId].ReturnCode = -99; ccDict.TryUpdate(rId, ccDict[rId], ccDict[rId]); if (ccDict[rId].RetryAttempts >= 5) { Console.WriteLine("Failed:" + rId +" Retry Attempts :" + ccDict[rId].RetryAttempts.ToString() +" :" + ccDict[rId].ExceptionMessage.ToString()); cancelToken.Cancel(); } } public class myRule { public Boolean RulePassed = true; public string ExceptionMessage =""; public int RetryAttempts = 0; public int ReturnCode = 0; public myRule() { RulePassed = false; ExceptionMessage =""; RetryAttempts = 0; ReturnCode = 0; } } |
为什么要明确地调用
看起来您试图在您的
最后,错误文本本身就说明了问题。不能修改正在迭代的同一集合。
启动第二个集合,并向其中添加要保留的值。
我觉得你用字典是办不到的。相反,你可以做一些类似于
此问题包含有关已修改的IT集合的详细信息;枚举操作可能无法执行