0

To preface, I believe I understand how list modification errors occur. You can't change a list while you're looping them, and in some cases, variables that are linked to the list (I think that's what's happening). I've also searched around quite a bit, but can't seem to find a situation similar to mine.

I'm using TMP UGUI for now as placeholder for a slot machine game I'm working on. I've removed a lot and simplified the code to better understand where the error is occurring. I made a separate list "nextSlotsToCheck" which the loop list will change to before the foreach statement occurs. I believe the list I am looping is not being edited while it is looping, but apparently I'm wrong. Please help.

private void checkSlots(List<GameObject> columns)
{
    // Get all slots in first column
    TextMeshProUGUI[] firstColumnSlots = columns[0].GetComponentsInChildren<TextMeshProUGUI>();

    // Check all slots in first column
    foreach (TextMeshProUGUI firstColumnSlot in firstColumnSlots)
    {
        
        List<TextMeshProUGUI> nextSlotsToCheck = new List<TextMeshProUGUI>();

        // Check following columns
        for (int i = 1; i <= columns.Count - 1; i++)
        {
            List<TextMeshProUGUI> slotsToCheck = new List<TextMeshProUGUI>();

            // Setup for first column check
            if (i == 1)
            {
                slotsToCheck.Add(firstColumnSlot);
            }
            else
            {
                slotsToCheck = nextSlotsToCheck;
            }

            // Check all previously matching slots
            foreach (TextMeshProUGUI currentSlot in slotsToCheck)
            {

                // Check all slots in next column
                foreach (TextMeshProUGUI nextSlot in columns[i].GetComponentsInChildren<TextMeshProUGUI>())
                {
                    nextSlotsToCheck.Add(nextSlot);
                }
            }
        }
    }
}
  • What are the suggested methods in the numerous dupes posted here, and how are they inadequate? – Ňɏssa Pøngjǣrdenlarp May 16 '22 at 01:01
  • From what I found, they only really address the common issue of changing the list that's running e.g. slotsToCheck.Add(nextSlot). I don't change the currently running list, I change a secondary list. – Jacob Lamattina May 16 '22 at 01:32

2 Answers2

2

When your columns-loop goes into that else-case because i != 1, you set:

slotsToCheck = nextSlotsToCheck;

So those two variables point to exactly the same list. Then you are iterating through slotsToCheck and inside it, modify nextSlotsToCheck. So you modify the same list while looping through it, hence the error.

You probably want to swap your slotsToCheck variable to the nextSlots list only after you have looped through it.

EDIT: Tip for the future: Please write in what line an error occurs when you ask. That makes things quicker.

AlexGeorg
  • 967
  • 1
  • 7
  • 16
  • So if I understand correctly, because I set the one list to equal the other, by changing the second list I am also changing the first? I figured the first list would just copy the contents of the second then continue being its own thing. Thank you for the answer, recommendation, and tip. Greatly appreciated. – Jacob Lamattina May 17 '22 at 02:03
  • So turns out moving the list change to after didn't resolve the issue. Instead, I created a loop to add the individual next slots to the list so there's no link between lists. I appreciate the help regardless! – Jacob Lamattina May 17 '22 at 02:18
  • Lists are "reference types". They are like an instance of a class where also each assignment just passes a reference to the same data around. Opposed to that are structs and basic types like ints, strings, floats. Those are "value types", meaning every assignment makes a copy. Copying large amounts of data is a performance impact by the way, therefore it would be bad if every assignment of a list would copy it all. Plus this allows you to pass a list to a method and change it there so that the changes are visible from all references. – AlexGeorg May 17 '22 at 07:18
  • Very useful information. I understand the concept, just didn't think of it when I was troubleshooting because I've never really had to deal with it. – Jacob Lamattina May 20 '22 at 15:45
-1

The problem was when I set

slotsToCheck = nextSlotsToCheck;

I didn't realize that this effectively links the lists so changing the second list in

nextSlotsToCheck.Add(nextSlot);

also changes the slotsToCheck list in

foreach (TextMeshProUGUI currentSlot in slotsToCheck)

My solution was to instead of linking the lists, loop through the second one and add each item individually to the first with

foreach (TextMeshProUGUI nextSlot in nextSlotsToCheck)
{
    slotsToCheck.Add(nextSlot);
}

I appreciate the help. Good luck!

  • The lists do not become "linked". You are assigning the reference from the first list to the reference for the second list. This makes the first list "point" to the second list. Here is an example of how this works: https://stackoverflow.com/questions/7477073/made-one-instance-of-a-class-equal-to-another-how-to-cancel-that (see the accepted answer). – Chadley08 May 18 '22 at 02:11