关于c#:由于List中的Foreach循环,游戏无法构建

Game will not build because of a Foreach loop in List

本问题已经有最佳答案,请猛点这里访问。

我正在尝试构建我的Unity项目,但是我不能,因为foreach循环有问题。下面是我收到的错误代码,但我不明白。有人能解释什么是可能的解决方案吗?或者为什么会发生这个错误?

InvalidOperationException:集合已修改;枚举操作可能无法执行。system.collections.generic.list`1+枚举器[unityengine.vector3].verifystate()(位于/users/builduser/buildsave/mono/build/mcs/class/corlib/system.collections.generic/list.cs:778)

system.collections.generic.list`1+枚举器[UnityEngine.vector3].moveNext()(位于/users/buildUser/buildSlave/mono/build/mcs/class/corlib/system.collections.generic/list.cs:784)

player_movement.update()(在assets/scripts/player/player_movement.cs:46处)

为了让上下文成为代码,你在屏幕上画一条线,它会创建一个向量列表,供玩家浏览。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
void Update()
{
    //when the player moves their finger accross the screen of the mouse button is held down
    if ((Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved) || (Input.GetMouseButton(0)))
    {
        //raycasthit variable called hit
        RaycastHit hit;
        //ray variable called ray
        Ray ray;
        //the ray variable is cast between the main camera and the mouse position
        ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        //if the physics racast hit then calulate the distance betwen the point (mouse position) and the camera
        if (Physics.Raycast(ray, out hit))
        {
            //save the positon as the nextPosition
            nextPosition = hit.point;
            //save the nextPositions point's yaxis
            nextPosition.y = yAxis;
            //if there are positions inside of the position list
            if (positionList.Count != 0)
            {
                //then for each vector3 position in the list
        Line 46  ===> foreach(Vector3 t in positionList)
                {
                    //if there is no posiiton in the list where one should be
                    if (nextPosition != t)
                    {
                        //then create a position
                        positionList.Add(nextPosition);
                    }
                }
            }
            else
            {   //otherwise create a position in the position list
                positionList.Add(nextPosition);
            }
        }
    }
}


之所以会出现这种异常,是因为您在迭代集合时试图修改它。有几种方法可以解决这个问题,但最好的方法可能是简单地测试条件(集合是否包含特定项),然后在测试为假时修改集合(添加项)。

Linq扩展名Any在这里很有用。如果集合中的任何项与条件匹配,则返回true。把一个!放在它前面意味着你正在寻找没有符合条件的物品的情况:

1
2
3
4
if (!positionList.Any(position => position == nextPosition))
{
    positionList.Add(nextPosition);
}

但您也可以在不使用Linq的情况下,使用Contains方法来完成此操作,该方法实际上更简单,而且可读性更高:

1
2
3
4
if (!positionList.Contains(nextPostition))
{
    positionList.Add(nextPostition);
}

请注意,这些答案也在修复代码中的错误。为了暴露bug并避免错误,可以在for循环内的集合上调用ToList(),如下所示:

1
2
3
4
5
6
7
8
9
foreach(Vector3 t in positionList.ToList())
{
    //if there is no posiiton in the list where one should be
    if (nextPosition != t)
    {
        //then create a position
        positionList.Add(nextPosition);
    }
}

这里对ToList()的调用实际上创建了列表的一个新副本,并对该副本进行迭代,因此在修改原始副本时不会发生冲突。但是,您会注意到,您的现有代码在每次遇到不匹配时都会将nextPosition添加到列表中,我认为这不是您的预期行为。


在遍历列表时,不能修改列表(即.Add())。

找到匹配的元素,然后根据需要添加:

1
2
if(positionList.FirstOrDefault(t => nextPosition == t) != null)
    positionList.Add(nextPosition);