C#:使用foreach或for循环从ArrayList中删除项目?

时间:2014-09-19 01:39:52

标签: c# for-loop arraylist foreach unity3d

我是一个使用C#进行编程和编程的菜鸟(之前我学过一些基本的Java)。我想在 Unity3D 中使用C#,我有一个问题:

使用for循环而不是foreach迭代删除ArrayList中的任何项目是否更好?

两者似乎都适合我。 Foreach产生的编码略少,但discussions on the Internet似乎有利于for循环。哪个更好,为什么?

for-loop版本:

public void RemoveUnitFromList(GameObject Unit) {
    if (SelectedUnitList.Count > 0) {
        for (int i = 0; i < SelectedUnitList.Count; i++) {
            GameObject ArrayListUnit = SelectedUnitList[i] as GameObject;
            if (ArrayListUnit == Unit) {
                SelectedUnitList.RemoveAt(i);
                // some other codes
            }
        }
    }
}

foreach版本:

public void RemoveUnitFromList(GameObject Unit) {
    if (SelectedUnitList.Count > 0) {
        foreach (GameObject ArrayListUnit in new ArrayList(SelectedUnitList)) {
            if (ArrayListUnit == Unit) {
                SelectedUnitList.Remove(ArrayListUnit);
                // some other codes
            }
        }
    }
}

编辑: 上面的任何一个代码片段对我来说都很好。我只想研究两者之间的区别。 但是,将in new ArrayList(SelectedUnitList)更改为in SelectedUnitList无效:

public void RemoveUnitFromList(GameObject Unit) {
    if (SelectedUnitList.Count > 0) {
        foreach (GameObject ArrayListUnit in SelectedUnitList) {
            if (ArrayListUnit == Unit) {
                SelectedUnitList.Remove(ArrayListUnit);
                // some other codes
            }
        }
    }
}

EDIT2: 上面的代码可能会产生以下错误:

InvalidOperationException: List has changed.
System.Collections.ArrayList+SimpleEnumerator.MoveNext () (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Collections/ArrayList.cs:141)
Mouse3.RemoveUnitFromList (UnityEngine.GameObject Unit) (at Assets/Scripts/Mouse3.cs:216)
Mouse3.Update () (at Assets/Scripts/Mouse3.cs:85)

让我解释一下。该方法在游戏中动态运行。 SelectedUnitList是用于收集RTS游戏中所选单元的ArrayList。该方法从ArrayList中删除取消选择的单位,因此Unit可以是0,1或更多。

Edit3(上次): 谢谢大家提供的所有信息。我认为@Seminda在评论中回答了我的问题。

4 个答案:

答案 0 :(得分:2)

来自foreach Loop上的MSDN文档:

  

foreach 语句用于遍历集合以获取所需的信息,但不能用于在源集合中添加或删除项目以避免不可预测的副作用。 如果您需要在源集合中添加或删除项目,请使用for loop

参考您的代码,请注意以下事项:

查看有关ArrayList的详细信息。通常最好使用List。列表不仅可以避免装箱或拆箱,而且还可以使代码更清晰,更容易出错。

<强>更新

foreach(你问题中的第二个片段)有效,因为你初始化了新的ArrayList。

foreach (GameObject ArrayListUnit in new ArrayList(SelectedUnitList))

您已初始化冗余ArrayList并仅将其用于迭代。但是当您从foreach循环中的ArrayList中删除它时,它来自实际的ArrayList,即SelectedUnitList。

结论

使用for loop来避免冗余并从ArrayList中删除。

答案 1 :(得分:1)

这两个都会有问题。我会继续使用foreach,这取决于是否制作了数组的完整副本或浅副本,你可能会收到错误,例如&#34;收集被修改;枚举操作可能无法执行。删除列表项&#34; 。我认为在这种情况下,foreach将在创建深层副本时起作用。但是对于大型列表,这可能效率低下,您可以从阵列中删除项目而无需创建整个阵列的副本。

我猜测SelectedUnitList中只有一个项目与Unit匹配?否则,使用for循环的第一个代码将失败。相反,你想要......

public void RemoveUnitFromList(GameObject Unit) {
    if (SelectedUnitList.Count > 0) {
        for (int i = SelectedUnitList.Count -1; i >= 0; i--) {
            GameObject ArrayListUnit = SelectedUnitList[i] as GameObject;
            if (ArrayListUnit == Unit) {
                SelectedUnitList.RemoveAt(i);
                DeactivateProjectorOfObject(ArrayListUnit);
            }
        }
    }
}

此代码向后循环删除项目,以便下一个迭代的项目不会受到上一次迭代中项目删除的影响。

假设只有一个项目匹配游戏单元......

GameObject arrayListUnit = SelectedUnitList.SingleOrDefault(u => u == unit);
DeactivateProjectorOfObject(arrayListUnit);
SelectedUnitList.Remove(unit);

此外,我不知道Unity开发人员正在进行什么,但您确实需要开始阅读有关编码标准的一些指导原则。没有编码标准我看过有变量以资本开头。

http://m.friendfeed-media.com/fc2fd89c8be6ace85f7bacedb14181d76ba6c8be

答案 2 :(得分:1)

我打算在您决定删除它时对每个对象执行处理,我首选的方法是在进行最终处理时构建要删除的项目列表,然后在单独的循环中删除项目。另请参阅使用类型列表(System.Collections.Generic.List&lt;&gt;)。如果您意外地将错误类型添加到列表中,则无类型列表只是在运行时询问问题。键入的列表可以帮助您编译时间以消除该问题。

我不得不问 - 如果你要传递一个特定的游戏对象要移除,为什么你需要循环任何东西? ArrayList.Remove接受一个对象参数,你真的不应该在你选择的单位列表中首先两次拥有相同的游戏对象。如果您这样做,您确实需要对构建SelectedUnitList的代码添加一些检查以防止添加重复项。另外..如果碰巧有重复的话,在同一个对象上调用DeactivateProjectorOfObject两次是安全的吗?

在这种情况下,您的代码归结为:


    public void RemoveUnitFromList(GameObject Unit) {
        DeactivateProjectorOfObject(unit);
        SelectedUnitList.Remove(unit);
    }

答案 3 :(得分:0)

它是一样的。在大多数情况下,我使用foreach,因为我生成的代码较少。我只在我想删除/添加当前集合的一些项目时使用。

如果您想要精确,可以修改一下代码:

public void RemoveUnitFromList(GameObject Unit) 
{
    if (SelectedUnitList.Count == 0) 
        return;

        foreach (GameObject ArrayListUnit in new ArrayList(SelectedUnitList)) 
        {
            if (ArrayListUnit != Unit) 
                continue;

                SelectedUnitList.Remove(ArrayListUnit);
                DeactivateProjectorOfObject(ArrayListUnit);


        }
    }
}