修改我正在迭代的字典

时间:2010-08-17 19:22:04

标签: c#

foreach(BruteforceEntry be in Entries.Values)
{
    if (be.AddedTimeRemove <= now)
        Entries.Remove(be.IPAddress);
    else if (be.Unbantime <= now && be.Unbantime.Day == DateTime.Now.Day)
        Entries.Remove(be.IPAddress);
}

抛出异常:

  

收藏被修改;枚举操作可能无法执行。

由于某种原因,它不再存在。

我知道你不能删除某些东西,而是以这种方式迭代它。我的问题是:我该如何解决?

7 个答案:

答案 0 :(得分:37)

您无法修改正在迭代的集合。在这种情况下,一个更好的解决方案是通过迭代字典来创建要删除的条目列表,然后遍历该列表,从字典中删除条目:

List<string> removals = new List<string>();                    
DateTime now = DateTime.Now;
foreach(BruteforceEntry be in Entries.Values)
{
    if (be.AddedTimeRemove <= now ||
        (be.Unbantime <= now && be.Unbantime.Day == DateTime.Now.Day))
    {
        removals.Add(be.IPAddress);
    }
}
foreach (string address in removals)
{
    Entries.Remove(address);
}

请注意,如果您使用的是.NET 3.5,则可以使用LINQ查询来表达第一部分:

List<string> removals = (from be in Entries.Values
                         where be.AddedTimeRemove <= now ||
                               (be.Unbantime <= now && 
                                be.Unbantime.Day == DateTime.Now.Day)
                         select be.IPAddress).ToList();

答案 1 :(得分:8)

简单地说:在迭代它时,你无法从集合中删除一个条目。

一种可能的解决方法是创建集合的浅表副本(例如使用ToList)并迭代它:

foreach(BruteforceEntry be in Entries.Values.ToList())
{
    // modify the original collection
}

答案 2 :(得分:2)

您可以将foreach(BruteforceEntry be in Entries.Values)更改为foreach(BruteforceEntry be in new List<BruteforceEntry>(Entries.Values))

这样你就不会修改你的收藏,而是修改它的副本。

答案 3 :(得分:2)

看起来您的问题是关于为什么异常被抛出以前的位置。正如其他答案陈述的那样,你通常不能改变你正在迭代的集合,但是你正在遍历Values集合,我认为它是字典中值的副本,而不是引用主字典集合本身。所以它不再有迭代和修改同样的问题。

答案 4 :(得分:1)

使用foreach进行迭代时,无法修改集合。相反,使用for循环迭代它。

答案 5 :(得分:1)

这(在我看来)是最简单的方法:

Dictionary<String, String> A = new Dictionary<string, string>(); //Example Dictionary
A.Add("A", "A"); //Example Values
A.Add("B", "B");
A.Add("C", "C");

for (int i = A.Count - 1; i >= 0; i--) //Loop backwards so you can remove elements.
{
     KeyValuePair<String, String> KeyValue = A.ElementAt(i); //Get current Element.
     if (KeyValue.Value == "B") A.Remove(KeyValue.Key);
}

在你的情况下:

for (int i = Entries.Count - 1; i >= 0; i--)
{
    KeyValuePair<String, BruteforceEntry> KeyValue = Entries.ElementAt(i);
    if (KeyValue.Value.AddedTimeRemove <= now)
         Entries.Remove(KeyValue.Key);
    else if (KeyValue.Value.Unbantime <= now && KeyValue.Value.Unbantime.Day == DateTime.Now.Day)
         Entries.Remove(KeyValue.Key);
}

答案 6 :(得分:0)

归结你的问题......

foreach(... ... in Entries.Values)
{
        Entries.Remove(...);

}

正如其他人所说,你在迭代时修改迭代器。

你可以像@David所说的那样使用for循环,但要确保从最后开始(反向迭代)。