我是一个使用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在评论中回答了我的问题。
答案 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);
}
}
}