C#:使用foreach或for循环从ArrayList中移除项

本文关键字:ArrayList 循环 使用 foreach for | 更新日期: 2023-09-27 18:23:43

无论是用C#编程还是用C#编程,我都是个新手(我以前学过一些基本的Java)。我正试图在Unity3D中使用C#,我有一个问题:

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

两者似乎都对我有效。Foreach产生的代码稍微少一些,但互联网上的讨论似乎倾向于循环。哪个更好,为什么?

对于循环版本:

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
            }
        }
    }
}

第2版:上述代码可能会产生以下错误:

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或更多。

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

C#:使用foreach或for循环从ArrayList中移除项

来自foreach Loop上的MSDN文档:

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

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

请参阅ArrayList的详细信息。通常最好使用列表。列表不仅可以避免装箱或取消装箱,还可以使代码更清晰、更不容易出错。

更新

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

foreach (GameObject ArrayListUnit in new ArrayList(SelectedUnitList))

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

震荡

使用for loop以避免冗余和从ArrayList中删除。

如果您计划在决定删除每个对象时对其进行处理,我的首选方法是在进行最终处理时构建一个要删除的项目列表,然后在单独的循环中删除这些项目。也要考虑使用类型化列表(System.Collections.Generic.List<>)。如果意外地将错误类型的内容添加到列表中,则非类型化列表在运行时会出现问题。键入的列表可以让你编译时间保护来消除这个问题。

我不得不问——如果你正在传递一个要删除的特定游戏对象,为什么你需要循环通过任何东西??Remove需要一个对象参数,你真的不应该在你选择的单位列表中有两次相同的游戏对象。如果您确实需要对构建SelectedUnitList的代码添加一些检查,以防止添加重复项。而且如果你碰巧有一个重复的对象,那么在同一个对象上调用DeactivateProjectorOfObject两次安全吗??

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

public void RemoveUnitFromList(游戏对象单元){停用对象的项目(单位);SelectedUnitList.Remote(单位);}

这两者都会有问题。我将远离使用foreach,这取决于是否制作了数组的完整副本或浅层副本。您可能会收到错误,例如"Collection was modified;enumeration operation may not executed.removing list item"。我认为在这种情况下,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

这是一样的。在大多数情况下,我使用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);

        }
    }
}