2010-03-05 11 views
4

J'ai cette fonction de minuterie, il me donne l'exception suivante.
La collection a été modifiée; opération d'énumération ne peut pas exécuter une fois que je supprime l'objet de la table de hachage.La collection a été modifiée; opération d'énumération peut ne pas exécuter pour hashtable

quelle est la solution à mettre en œuvre des fonctionnalités similaires

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); 
     } 
     } 
    } 

Répondre

10

La manière traditionnelle est, dans votre boucle foreach, pour recueillir les éléments à supprimer dans, par exemple, une liste. Puis, une fois la boucle foreach est terminée, faire une autre foreach sur cette liste (pas plus tMap cette fois-ci), appelant 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

Il est important de souligner que la sécurité du filetage n'est pas vraiment un facteur important ici. Vous obtiendriez la même erreur sans tenir compte du fait qu'un thread ou plusieurs threads se mêlaient de l'énumération de votre collection. (Bien sûr, je peux voir pourquoi vous voulez le limiter à un seul thread.) – razlebe

2

Vous pouvez faire une liste temporaire et ajoutez les ID à supprimer dans cette liste. Ensuite, après la fin de votre boucle, supprimez tous les éléments de cette liste:

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); 
     } 
    }