代码不会退出foreach块

时间:2010-05-28 03:00:57

标签: c# list

我有以下C#代码段,它接受一个列表,找到准备更新的对象,然后将它们推入临时列表,从主列表中删除,然后继续它的快乐方式。我的问题是循环通过我的主列表的foreach块不会退出。

 TempLog.Clear();   //Ensure TempLog is empty
 foreach (CLogger ready in PlayerLog)
 {
      if (ready.UpdateReady == true)  // Record is ready to be updated in database
      {
           TempLog.Add(ready);  // Add record to templog
           PlayerLog.Remove(ready);  // Remove from playerlog
      }
 }
              <----  Never reaches this point
 if (TempLog.Count > 0)  // Just check that templog isn't empty
 {
      new Thread(Update).Start();  // Run update code 
 }

我已经进行了大量的调试,我可以看到PlayerLog从1开始,TempLog为0,然后进入foreach循环,选择记录UpdateReady标志打开,TempLog转到1,PlayerLog转到0,然后它就会停止..没有错误,只是停止..

感谢您的帮助:)

5 个答案:

答案 0 :(得分:14)

当您迭代其枚举器时,您正在修改PlayerLog,这是一个很大的禁忌。

更好的选择是迭代PlayerLog的副本,同时修改原始的PlayerLog:

foreach (CLogger ready in new List<PlayerLogType>(PlayerLog))
 {
      if (ready.UpdateReady)  // Please don't compare boolean values against true...
      {
           TempLog.Add(ready);
           PlayerLog.Remove(ready);
      }
 }

或者,您可以使用传统的for循环。就个人而言,我喜欢从最后开始,因为我知道我将删除项目,所以我不必重新调整索引:

for (int i = PlayerLog.Count - 1; i >= 0; i--)
{
      var ready = PlayerLog[i];
      if (ready.UpdateReady)
      {
           TempLog.Add(ready);
           PlayerLog.RemoveAt(i);
      }
}

答案 1 :(得分:1)

奇怪的是,当你试图改变你正在迭代的集合时,它应该抛出异常。我这样做:

var ready = PlayerLog.Where(c => c.UpdateReady).ToArray();
if (ready.Any())
{
    TempLog.Clear();  //Ensure TempLog is empty
    TempLog.AddRange(ready);
    foreach (CLogger c in ready) PlayerLog.Remove(c);
    new Thread(Update).Start();  // Run update code 
}       

此外,这看起来有点像你正在尝试构建生产者/消费者队列。如果是这样,你应该看看微软的Concurrency and Coordination Runtime,现在奇怪的是Microsoft Robotics Studio

答案 2 :(得分:1)

这是一个使用lambda表达式的简单方法:

TempLog.Clear();
TempLog.AddRange(PlayerLog.Where(a => a.UpdateReady));
TempLog.ForEach(a => PlayerLog.Remove(a));

答案 3 :(得分:0)

正如Mark指出的那样,当您修改正在循环的集合时,foreach循环经常会中断。

在这种情况下,您可以避免复制列表,因为您有一个临时列表可供使用。如果TempLog的最终内容无关紧要,请尝试:

 TempLog.Clear();   // initial "new" list
 foreach (CLogger ready in PlayerLog)
 {
      if (ready.UpdateReady != true)
           TempLog.Add(ready); // item being kept (not removed) - add to "new" list
 }

 if (TempLog.Count != PlayerLog.Count)  // check if any items were not kept
 {
      PlayerLog.Clear();
      PlayerLog.AddRange(TempLog);
      new Thread(Update).Start();  // Run update code 
 }

另一个解决方案是将要删除的项目列表存储在队列或堆栈中,然后在foreach循环后将它们全部删除。

答案 4 :(得分:0)

Mark是对的,但是使用for循环,这样就不会浪费内存。