2

ディクショナリ内のアイテムがすべての処理を通過する場合、それを削除したいディクショナリがあります。

            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 を再実行します。

4

6 に答える 6

3

同時に反復している場合、コレクションからアイテムを削除することはできません。ただし、削除するすべての要素を別のコレクションに保存することができます。

次に、列挙が完了したら、リストを反復処理して、元のコレクションから各項目を削除できます。

または、 ac# Dictionary から述語に一致する複数のアイテムを削除する最良の方法を確認してください。. それはかわいい。ユーザー@JaredParの厚意により、受け入れられた回答の抜粋は次のとおりです。

foreach ( var s in MyCollection.Where(p => p.Value.Member == foo).ToList() ) {
  MyCollection.Remove(s.Key);
}
于 2013-04-30T21:53:24.953 に答える
1

2 番目のコレクションを開始し、保持する値を追加します。

于 2013-04-30T21:56:48.987 に答える
1

GetEnumerator()を使用する代わりに明示的に呼び出すのはなぜforeachですか? foreach声明はあなたを助けるためにそこにあります。この場合、MoveNext()ループで使用しますが、Currentプロパティを読み取ることはありません。

で使用しようとしているようですが、スレッドセーフなタイプであると確信しParallel.ForEachdictObjいますか? おそらくそうではありません。そのタイプは何ですか?

最後に、エラー テキストがそれ自体を物語っています。繰り返し処理している同じコレクションを変更することはできません。

于 2013-04-30T21:59:10.717 に答える
1

私が行った会話から: Jeppe Stig Nielsen は、ConcurrentDictionary

これは、ディクショナリから (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;
        }
    }
于 2013-05-02T16:40:30.387 に答える