2010-03-05 2 views
4

У меня есть эта функция таймера, она дает мне следующее исключение.
Коллекция была изменена; операция перечисления может не выполнить после удаления объекта из хеш-таблицы.Коллекция была изменена; операция перечисления может не выполняться для hashtable

что такое решение реализовать аналогичные функциональные возможности

void timerFunction(object data) 
    { 
    lock (tMap.SyncRoot) 
    { 
     foreach (UInt32 id in tMap.Keys) 
     { 
     MyObj obj=(MyObj) runScriptMap[id]; 
     obj.time = obj.time -1; 
     if (obj.time <= 0) 
     {      
      tMap.Remove(id); 
     } 
     } 
    } 

ответ

10

Традиционный способ, в цикле Еогеасп, собирать предметы, которые будут удалены в, скажем, список. Тогда, как только цикл Еогеасп закончил, сделать еще Еогеасп над этим список (не над TMAP на этот раз), называя tMap.Remove:

void timerFunction(object data) 
{ 
    lock (tMap.SyncRoot) 
    { 
    List<UInt32> toRemove = new List<UInt32>(); 

    foreach (UInt32 id in tMap.Keys) 
    { 
     MyObj obj=(MyObj) runScriptMap[id]; 
     obj.time = obj.time -1; 
     if (obj.time <= 0) 
     {      
     toRemove.Add(id); 
     } 
    } 

    foreach (UInt32 id in toRemove) 
    { 
     tMap.Remove(id); 
    } 
    } 
} 
+0

Стоит отметить, что безопасность потоков на самом деле не является фактором. Вы получите ту же ошибку, независимо от того, вмешивался ли один поток или несколько потоков в вашу среднюю перечисление коллекции. (Хотя, конечно, я вижу, почему вы хотите ограничить его одним потоком.) – razlebe

2

Вы могли бы сделать временный список , и добавьте идентификаторы для удаления в этот список. Затем, после завершения цикла, удалите все элементы из этого списка:

void timerFunction(object data) 
    { 
    lock (tMap.SyncRoot) 
    { 
     IList<UInt32> toDelete = new List<UInt32>(); 
     foreach (UInt32 id in tMap.Keys) 
     { 

     MyObj obj=(MyObj) runScriptMap[id]; 
     obj.time = obj.time -1; 
     if (obj.time <= 0) 
     {      
      toDelete.add(id); 
     } 
     } 
     foreach(UInt32 i in toDelete) 
     { 
      tMap.Remove(i); 
     } 
    }