【问题标题】:Remove an item from a generic list while in a foreach [duplicate]在foreach中从通用列表中删除一个项目[重复]
【发布时间】:2013-09-03 11:07:23
【问题描述】:

我现在正在编写拾音器(硬币等),但是当你捡起东西时......它不再躺在地上了。

但我遇到了一个例外:System.InvalidOperationException。由map.Remove()引起,由foreach循环抛出。

那么,如何从列表中正确删除取件?

foreach (CollisionTiles tile in map.CollissionTiles)
{
    if (!tile.isTransparant)
        player.Collision(tile.Rectangle, map.Width, map.Height);
    else
    {
        if (player.PickUp(tile, map.Width, map.Height))
            map.Remove(tile);
    }

    camera.Update(player.Position, map.Width, map.Height);
}

map.Remove() 无效:

public void Remove(CollisionTiles tile)
{
    this.collissionTiles.Remove(tile);
}

【问题讨论】:

  • 在修改集合时,您不能使用foreach 遍历集合。将for与索引器一起使用,从最大的索引开始向下
  • 顺便说一句 - 您真的要更新相机为每个图块,而不是在循环完成后更新一次?
  • @ReedCopsey 我知道。我做得很快,你知道会发生什么...

标签: c#


【解决方案1】:

最简单的方法是记住所有要删除的元素,然后再删除:

var tilesToRemove = new List<CollisionTiles>();
foreach (var tile in map.CollisionTiles)
{
    if (!tile.IsTransparent)
    {
        player.Collision(tile.Rectangle, map.Width, map.Height);
    }
    else if (player.PickUp(tile, map.Width, map.Height))
    {
        tilesToRemove.Add(tile);
    }
    camera.Update(player.Position, map.Width, map.Height);
}

// Remove all the ones we didn't want
foreach (var tile in tilesToRemove)
{
    map.Remove(tile);
}
// Potentially call camera.Update here? We don't know if it uses the tiles

(顺便说一下,不清楚为什么你经常调用camera.Update - 你不能在循环之后调用一次吗?)

【讨论】:

  • 除了它可能使用更少的内存之外,为什么您更喜欢在 foreach 中删除而不是 map.Except(tilesToRemove)?这似乎是更多的 LINQ 做事方式......
  • @evanmcdonnal:map 本身并不是一个列表,map.Except 实际上并没有从列表中删除项目。例如,我们不知道同一个列表还有哪些其他引用 - 否则是的,我们可能会使用 map.CollisionTiles = map.CollisionTiles.Except(tilesToRemove).ToList()
  • 啊,我没有注意到该列表实际上是地图上的一个属性。我只是想将Except 返回的IEnumerable 分配给一个局部变量。
【解决方案2】:

使用for 循环而不是foreach

for (int i = map.CollisionTiles.Count - 1; i >= 0; i--)
{
    CollisionTile tile = map.CollisionTiles[i];
    if (!tile.isTransparant)
        player.Collision(tile.Rectangle, map.Width, map.Height);
    else
    {
        if (player.PickUp(tile, map.Width, map.Height))
            map.Remove(tile);
    }

    camera.Update(player.Position, map.Width, map.Height);
}

【讨论】:

  • 您假设可以颠倒迭代顺序。情况可能确实如此,但我认为最好指定这一点。
  • 不会声明tile吗?你的意思是map.CollisionTiles[i],而不是tile
  • @davidsbro:很好,谢谢!我更新了我的答案。
猜你喜欢
  • 2019-10-26
  • 2015-12-06
  • 2015-07-20
  • 2020-03-16
  • 2012-02-15
  • 1970-01-01
  • 2011-09-29
  • 2013-08-03
  • 1970-01-01
相关资源
最近更新 更多