首页 > 解决方案 > foreach 中列表的奇怪行为

问题描述

我有一个在运行时跟踪“活动”对象的列表。当我在这个列表中的项目中应用一些行为时,我发现了一些奇怪的东西(至少对我来说),例如,假设我想伤害当前场景中的每个敌人,所以(项目是自定义类的列表)

if (Input.GetKeyDown(KeyCode.C))
{
    var enemiesWithLife = enemiesInScene.Items.FindAll(enemy => enemy.life > 1);

    foreach (var enemy in enemiesWithLife)
        enemy.TakeDamage(1);
}

上面的代码按预期工作但是如果我想对所有敌人应用一些东西并尝试一些东西

if (Input.GetKeyDown(KeyCode.C))
{
    foreach (var enemy in enemiesInScene.Items)
        enemy.TakeDamage(1);
}

当我按“C”时,只有 1 个敌人“TakeDamage”,并且在迭代期间修改了有关列表的错误

但是,如果我尝试相同的代码,但之前进行了查找,如

if (Input.GetKeyDown(KeyCode.C))
{
    var allEnemies = enemiesInScene.Items.FindAll(enemy => true);

    foreach (var enemy in allEnemies)
        enemy.TakeDamage(1);
}

事情再次按预期工作......为什么?

编辑

评论中询问的代码:

public void TakeDamage(int damage)
{
    if (currentLife <= 0)
        return;

    currentLife -= damage;

    if (currentLife <= 0)
        Die();
    else
        TakeHit();
}

EnemiesInScene 是一个 RuntimeSet

public class RuntimeSet : ScriptableObject
{
    public List<RuntimeItem> Items = new List<RuntimeItem>();

    public void Add(RuntimeItem thing)
    {
        if (!Items.Contains(thing))
            Items.Add(thing);
    }

    public void Remove(RuntimeItem thing)
    {
        if (Items.Contains(thing))
            Items.Remove(thing);
    }
}

运行时项

public class RuntimeItem : LazyComponents
{
    public RuntimeSet runtimeSet;

    private void OnEnable()
        => runtimeSet.Add(this);

    private void OnDisable()
        => runtimeSet.Remove(this);
}

并且 LazyComponents 只是一个惰性方法包装器,它继承自 monobehaviour 以获取一些组件作为rigidbody2d 等......

标签: unity3d

解决方案


for (int i = list.Count - 1; i != -1; i--)
    list.RemoveAt(i); // replace with useful code that can modify this list

推荐阅读