C# while循环中的字典和删除字典中的项

C# while循环中的字典和删除字典中的项,c#,C#,我有一个字典,如果字典中的项目经过所有处理,我想删除它 var dictEnum = dictObj.GetEnumerator(); while (dictEnum.MoveNext()) { Parallel.ForEach(dictObj, pOpt, (KVP, loopState) => { pro

我有一个字典,如果字典中的项目经过所有处理,我想删除它

            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>
               }
            }
var dictEnum=dictObj.GetEnumerator();
while(dictEnum.MoveNext())
{
Parallel.ForEach(dictObj,pOpt,(KVP,loopState)=>
{
processAndRemove(KVP.Key);
});
}
私有void processAndRemove(字符串keyId)
{
尝试
{
dictObj.Remove(keyId);
}捕获(例外情况除外){
...

如果同时对集合进行迭代,则无法从集合中删除该项。 但是,您可以将要删除的所有元素存储在单独的集合中

然后,当您完成枚举后,可以迭代列表以从原始集合中删除每个项

或者,也可以去看看。它很漂亮。用户@JaredPar提供的公认答案摘录是:

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

我不认为你可以用字典来做这件事。相反,你可以做一些像
dictionary.Values.ToList()
,去掉你想要的,然后调和差异


这个问题有更多关于它的信息

开始第二个集合,并向其中添加您想要保留的值。

正如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);
}
var toRemove=new Dictionary()//不管它是什么类型
Parallel.ForEach(dictObj,pOpt,(KVP,loopState)=>
{
toRemove.Add(KVP);
});
foreach(toRemove中的var项目)
{
dictObject.Remove(item.Key);
}

为什么要显式调用
GetEnumerator()
而不是使用
foreach
?有
foreach
语句可以帮助您。在这种情况下,您在循环中使用
MoveNext()
,但从不读取
Current
属性

看起来您试图在
dictObj
上使用
Parallel.ForEach
,但您确定它是线程安全的类型吗?可能不是。它的类型是什么


最后,错误文本不言而喻。您不能修改正在迭代的同一个集合。

来自我的对话:Jeppe Stig Nielsen产生了一个想法,尝试使用
ConcurrentDictionary

这是我的测试代码,在这里我可以从字典中删除项目(从Parallel.Foreach循环中),而
循环将继续,直到
计数==0或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;
        }
    }
公共静态ConcurrentDictionary ccDict=新ConcurrentDictionary();
尝试
{
而(ccDict.Count>0)
{
Parallel.ForEach(ccDict,pOptions,(KVP,loopState)=>
{
//这是一个标志,它告诉循环如果已请求取消,就退出循环
pOptions.CancellationToken.ThrowIfCancellationRequested();
processRule(KVP.Key、KVP.Value、loopState);
});//Parallel.ForEach循环的结束
}
}
捕获(例外情况除外)
{
Console.WriteLine(例如Message.ToString());
Console.ReadLine();
}
公共静态int processRule(字符串rId、myRule规则、ParallelLoopState loopState)
{
尝试
{
如果(rId==“001”| | rId==“002”)
{
如果(rId==“001”&&ccDict[rId].RetryAttempts==2)
{
操作通过(rId);
返回0;
}
操作失败(rId);
}
其他的
{
操作通过(rId);
}
返回0;
}
捕获(例外情况除外)
{
Console.WriteLine(“失败:+ex.Message.ToString());
返回-99;
}
}
私有静态无效操作已通过(字符串rId)
{
//正常运行
ccDict[rId].RulePassed=true;
ccDict[rId]。例外消息=”;
ccDict[rId].ReturnCode=0;
WriteLine(“传递:“+rId+”重试尝试:“+ccDict[rId].RetryAttempts.ToString());
规则值;
ccDict.TryRemove(rId,out值);
}
私有静态无效操作失败(字符串规则ID)
{
//这就像发生了异常一样
int retryCount=0;
ccDict[rId].RulePassed=false;
ccDict[rId].RetryAttempts=ccDict[rId].RetryAttempts+1;
ccDict[rId].ExceptionMessage=“强制失败”;
ccDict[rId].ReturnCode=-99;
ccDict.TryUpdate(rId,ccDict[rId],ccDict[rId]);
如果(ccDict[rId].RetryAttempts>=5)
{
Console.WriteLine(“失败:“+rId+”重试尝试:“+ccDict[rId].RetryAttempts.ToString()+”:“+ccDict[rId].ExceptionMessage.ToString());
cancelToken.Cancel();
}
}
公共类myRule
{
public Boolean RulePassed=true;
公共字符串例外消息=”;
公共整数重试次数=0;
public int ReturnCode=0;
公共规则()
{
RulePassed=false;
例外消息=”;
重试次数=0;
ReturnCode=0;
}
}

根据我的研究,在执行while循环时,您需要字典中有一个枚举器。我正在探索while循环的用法,以便它能够继续运行所有失败的项,而不必启动另一个进程。@JeffV
dictObj
字段的类型是什么?@JeffV如果这意味着
System.Collection