修改我正在迭代的字典

Bas*_*ser 26 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);
}
Run Code Online (Sandbox Code Playgroud)

抛出异常:

收集被修改; 枚举操作可能无法执行.

出于某种原因,它已经不复存在了.

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

Jon*_*eet 42

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

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);
}
Run Code Online (Sandbox Code Playgroud)

请注意,如果您使用的是.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();
Run Code Online (Sandbox Code Playgroud)

  • 非常感谢.我有一个问题,你喜欢这个,而不是使用.ToList()通过一个副本迭代,因为这是一个较小的编辑. (2认同)
  • @Basser:嗯,首先,这可能会减少内存占用.它也只迭代整个集合一次 - 您当前的解决方案迭代一次以构建列表,然后迭代该列表.不要误解我的意思 - 它会起作用......我只是喜欢这种方法. (2认同)

dig*_*All 10

简单地说:当您迭代它时,您无法从集合中删除条目.

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

foreach(BruteforceEntry be in Entries.Values.ToList())
{
    // modify the original collection
}
Run Code Online (Sandbox Code Playgroud)

  • @Dave,迭代器是从ToList List实例创建的,修改是针对Entries的.这有效. (6认同)