簡體   English   中英

while循環中的字典和刪除字典中的項目

[英]dictionary in while loop and removing items in dictionary

我有一個字典,如果字典中的項目通過我要刪除它的所有處理。

            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>
               }
            }

我希望循環繼續處理字典中的所有剩余項目(未刪除)。

但是,我收到了一個錯誤。 當我運行此代碼的更簡單版本時,我收到一條消息說明:

收集被修改; 枚舉操作可能無法執行

有沒有辦法用字典做到這一點?

更新:

只是為了給出更多背景。 這背后的想法是如果dictObj中還有項目,循環繼續運行。 因此,如果我從10和8開始,我想重新運行直到他們沒有通過的2。

正如Jalayn所說,在你列舉它時,你不能從一個系列中刪除它。 您必須重寫代碼,以便將其添加到另一個集合,然后枚舉該集合並刪除原始集合中的項目。

就像是:

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);
}

如果您在同一時間迭代它,則無法從集合中刪除該項。 但是,您可以將要刪除的所有元素存儲在單獨的集合中。

然后,當您完成枚舉后,您可以遍歷列表以從原始集合中刪除每個項目。

或者,查看從ac#Dictionary中刪除與謂詞匹配的多個項目的最佳方法? 好漂亮啊。 用戶@JaredPar提供的接受的答案摘錄是:

foreach ( var s in MyCollection.Where(p => p.Value.Member == foo).ToList() ) {
  MyCollection.Remove(s.Key);
}

我認為你不能用字典做到這一點。 相反,您可以執行類似Dictionary.Values.ToList() ,刪除您想要的內容,然后協調差異。

這個問題有更多關於它的信息收集被修改; 枚舉操作可能無法執行

啟動第二個集合並在其中添加要保留的值。

為什么要顯式調用GetEnumerator()而不是使用foreach foreach聲明可以幫助您。 在這種情況下,您在循環中使用MoveNext() ,但您從未讀過Current屬性。

看起來你試圖在你的dictObj上使用Parallel.ForEach ,但你確定它是一個線程安全的類型嗎? 可能不是。 它的類型是什么?

最后,錯誤文本說明了一切。 您無法修改正在迭代的同一個集合。

從我的談話中:Jeppe Stig Nielsen產生了嘗試ConcurrentDictionary的想法

這是我的測試代碼,我可以從Dictionary中刪除項目(從Parallel.Foreach循環中), while循環繼續,直到count == 0 or the retryAttempts > 5

    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;
        }
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM