根据列表

时间:2017-11-09 13:42:29

标签: c#

我正在尝试使用预制件填充面板,当播放器有升级可用但是我的当前代码出错并且在控制台中我收到以下错误

InvalidOperationException: Collection was modified; enumeration operation may not execute.

以下代码块导致此错误

GameObject currentTable = upgradeTable[upgradeTableLevel - 1];
        if(GameManager.Instance.AvailableUpgrades != null){
            foreach(Upgrade upg in GameManager.Instance.AvailableUpgrades){
                GameObject go = Instantiate(upgradePrefab,currentTable.transform);
                go.GetComponentInChildren<Text>().text = upg.ToString() + "(level: " + GameManager.Instance.upgrades[upg] + ")";
                go.GetComponentInChildren<Button>().GetComponentInChildren<Text>().text = "Buy for " + GameManager.Instance.GetNextCost(GameManager.Instance.upgrades[upg]).ToString() + " units";
                GameManager.Instance.DisplayedUpgrades.Add(upg);
                GameManager.Instance.AvailableUpgrades.Remove(upg);
            }
        }

此代码也会产生多个预制件

目标行为适用于List&#34; AvailableUpgrades&#34;当这些代码完成时,可以使用升级来填充升级

public void UpdateAvailableUpgrades(){
        foreach (KeyValuePair<Upgrade,int> cur in upgrades) {
            if (units >= GetNextCost(cur.Value)) {
                if (!AvailableUpgrades.Contains (cur.Key) && !DisplayedUpgrades.Contains(cur.Key)) {
                    AvailableUpgrades.Add (cur.Key);
                }
            }
        }
    }

升级完成后,此代码块称为

#region UpgradeTable
        int upgradeTableLevel = GameManager.Instance.FetchUpgradeLevel(Upgrade.UpgradeTable);
        upgradeTable[upgradeTableLevel - 1].SetActive(true);
        foreach(GameObject go in upgradeTable){
            if(go != upgradeTable[upgradeTableLevel - 1]){
                go.SetActive(false);
            }
        }

        //TODO
        //Add a way to find the currently active table and add new upgrades prefab there
        //TEMP SOLUTION
        GameObject currentTable = upgradeTable[upgradeTableLevel - 1];
        if(GameManager.Instance.AvailableUpgrades != null){
            foreach(Upgrade upg in GameManager.Instance.AvailableUpgrades){
                GameObject go = Instantiate(upgradePrefab,currentTable.transform);
                go.GetComponentInChildren<Text>().text = upg.ToString() + "(level: " + GameManager.Instance.upgrades[upg] + ")";
                go.GetComponentInChildren<Button>().GetComponentInChildren<Text>().text = "Buy for " + GameManager.Instance.GetNextCost(GameManager.Instance.upgrades[upg]).ToString() + " units";
                GameManager.Instance.DisplayedUpgrades.Add(upg);
                GameManager.Instance.AvailableUpgrades.Remove(upg);
            }
        }
        #endregion

这里发生的事情是我获取表级别(抓取当前活动的表和其他不相关的东西所需)一旦我们到达//temp solution我抓住当前活动的表。然后检查AvailableUgrades中是否有任何升级,如果是这样,我循环列表以在列表末尾的列表中为每次升级实例化新的升级预制件,从{{1}中删除升级}并添加到AvailableUpgrades我添加了2个列表来处理这个以解决它不断产生新预制件的问题,但它仍在产生它们

那么如何修复脚本以提供预期的行为?

2 个答案:

答案 0 :(得分:2)

错误解释清楚,您在此列举的集合;

foreach(Upgrade upg in GameManager.Instance.AvailableUpgrades){
 ...

然后在这里修改,它仍然在循环内(枚举);

         GameManager.Instance.AvailableUpgrades.Remove(upg);
 }

您只需要维护要删除的升级列表,然后在循环结束后将其删除。 因此,创建一个新的升级列表,更改.Remove以将其添加到此新列表[upgradesToRemove.Add(upg)],然后在循环完成后,您可以从GameManager中删除新列表中的所有升级。 Instance.AvailableUpgrades,因为当你在循环之外时它不再被枚举。 EZ。

答案 1 :(得分:1)

正如Milney所提到的,foreach循环不允许您出于安全原因更改迭代的枚举。避免这种操作通常是一种很好的做法,因为它很容易导致令人讨厌的错误。无论如何你都希望这样做(因为我自己做了几次),你可以用for循环而不是foreach来完成:

for (int i = 0; i < GameManager.Instance.AvailableUpgrades.Count; i++) {
    // Do you thing
    if (/*some possible condition*/) {
        GameManager.Instance.DisplayedUpgrades.Add(/*some new Object*/);
    }
    if (/*another possible condition*/) {
        GameManager.Instance.AvailableUpgrades.RemoveAt(i);
        i--; // Since i is pointing to current object that was just removed
        // Otherwise you'd skip one object
    }
}

我再说一遍。 此类代码很容易导致难以跟踪的错误,对于项目中的新手来说也很难理解,因此建议您尽量避免在枚举过程中弄乱尽可能循环。

编辑或者......因为我注意到您的代码没有检查删除每个对象的条件,所以您可以在循环后调用GameManager.Instance.AvailableUpgrades.Clear()删除所有对象。