InvalidOperationException: Collection was modified; enumeration operation may not execute.

Hey,
I am a medium skilled coder but not too familiar with c#. I have found a lot on this error but nothing helps because my array is a Quaternion array and none of the solutions I have found work. In the code below the quaternion value stored in pellets[ i ] is changed in the code and when it loops back it throws the error.

error: InvalidOperationException: Collection was modified; enumeration operation may not execute.

I am trying to find out which line of code is changing the array value and how can I prevent it from happening or do a work around of some sort. Thank you.

[PunRPC]
    void RPC_Shotgun()
    {
        //play sound
        audioS.clip = sound_shoot;
        audioS.Play();
        audioS.time = 0.0f;
        Quaternion q;

        //create the shooting bullet
        int i = 0;
       
        foreach (Quaternion quat in pellets)
            {
            pellets[i] = Random.rotation;
            GameObject inst_pellet = Instantiate(shellPrefab, w_nozzle.position, Quaternion.Euler(0, 0, 0));
            inst_pellet.transform.forward = w_nozzle.right;
            inst_pellet.transform.rotation = Quaternion.RotateTowards(inst_pellet.transform.rotation, pellets[i], spreadAngle);
            inst_pellet.transform.SetParent(bulletCointainer.transform);
            Shell bulletSc = inst_pellet.transform.GetChild(0).GetComponent<Shell>();
            bulletSc.objective = hit.point;
            bulletSc.playerORigin = PV.Owner;
            //dump values of rotation
            Vector3 rot = new Vector3(inst_pellet.transform.rotation.eulerAngles.x, inst_pellet.transform.eulerAngles.y, inst_pellet.transform.eulerAngles.z);
            i++;

        }
        //a bullet is created and subtracted from the number of bullets
        nb_bullets -= 1;
    }

what is the type of pellets?
I wouldā€™ve typed the solution if a medium coder would give me the necessary tools to work with.

edit:
I assume itā€™s just a list (edit2: sorry Iā€™ve just seen you said itā€™s an array)

  1. you can fall back to a for loop, itā€™s actually what I would recommend anyway, because a) youā€™re using a counter and b) foreach is not terribly efficient for such use cases and doesnā€™t not improve readability in your case
  2. you can make a copy of the list before you run this loop (probably too expensive, but still, you could make a non-allocating recyclable list, maybe even private static for this purpose)
  3. you could always try and comment the inner block then uncomment each line to see what exactly affects the collection

edit2:
well, because itā€™s an array, please donā€™t use a foreach in this case.
itā€™s an absolute overkill for a nimble structure such as 1D array that should run fast and be friendly to your memory composition. use a for and be happy.

it helps to learn what exactly foreach does under the hub. itā€™s not a bad programming practice, but when youā€™re making games youā€™re supposed to squeeze your performance out of anything. in this case the compiler has to make a hidden enumerator class for your array, and to call bunch of methods to be able to traverse it, and then you also stumble onto this error, which means there is an overhead of error checking in the background, which is just mindboggling.

my general recommendation would be to use foreach when:

  1. a type youā€™re iterating is truly an enumerable: lacks an index, is unordered, or has a complex record, like dictionaries have key-value pairs (though dictionaries also donā€™t have indices and are unordered)
  2. you call this seldomly and it drastically improves readability of your code
  3. you have a really clever enumerable type

if not, use fors and whiles.

1 Like

if you need to get a good grasp on C# feel to be able to discern best practices on your own, ask me on its features here, Iā€™ll try to elaborate whatā€™s what. Iā€™ve been there 10 years plus ago, coming from a different environment, I know what itā€™s like. and it was worse back then, it used to be very boilerplate-y, but in the meantime C# became much more slick and productive, tbh.

btw, I believe this is ā€œchangingā€ the collection. itā€™s dumb.

please do

for(int i = 0; i < pellets.Length; i++) {
  pellet[i] = Random.rotation;
  ...
}

though now that Iā€™ve written this, why do you need an array if all you do is overwriting its elements right off the bat?

I want to thank you for the help and apologize in advanced for not being a ā€˜mediumā€™ coder but a stupid noob. The following code is what I used to create the list and fill it with starting values. All of this is from a tutorial I followed that was close to what I want to achieve.

List pellets;

public void Awake()
{
pellets = new List(pelletCount);
for (int i=0;i <pelletCount; i++)
{
pellets.Add(Quaternion.Euler(Vector3.zero));
}
}

It is a list. What I am attempting to do is create a shotgun effect, firing a number of pellets out in one shot, randomly changing the angle of each pellet. Once each is instantiated, it is treated like a bullet and the resulting prefab has the controls for velocity and collisions and this script just instantiates it and points it in the right direction.

I found answers that say to copy the list, but they donā€™t seem to work in this case as the toList isnā€™t available, if that helps.

1 Like

10 years ago I was a pretty serious VB.Net programmer. I have only recently started to program in Unity with C#. I have a lot to learn.

1 Like

In general, thatā€™s a Linq feature (IEnumerable extension), you need to using System.Linq; to get it.

While weā€™re at it, I donā€™t recommend using Linq in game dev, unless you have a really good reason: i.e. it makes your code massively more compact and/or readable or (in rare circumstances) improves your performance (by being more memory-aware or cycle-conservative, but this is rarely the case). Use it seldomly though, and when you feel you get things under control, especially stuff like copying large objects heap to heap and such.

Linq is basically ā€˜filthyā€™ because it does things that are too cumbersome for the most part, even if they look nimble. Itā€™s a compilation thing (google up c# lowering) and not essentially a feature of CLR, like that foreach you used that can bite your ass off if you donā€™t master the fundamentals first.

So what Iā€™m saying is that you need to have a pretty good understanding of what Linq does, if you want to use it competently. I have nothing against it but its simplicity is an enticing gateway to a pretty bad abuse/misuse.

This is why Iā€™ve offered my help. There is A LOT to learn. But itā€™s really rewarding. I was angry at C# at first, it made me really angry, as it was very cumbersome to write when I started, coming off from a far less strict but much more productive environment.

The simplest of things were a pain to do, so many ways just to loop over things, not a single best way to do anything because of legacy stuff holding you back, no useful mnemonics to gather around patterns in your head, so few ways to manipulate an array, but no associative arrays, callbacks stupidly hard to implement, then thereā€™s Linq, delegates, generics, structs, too many stuff going on all at once. But I was persistent, and had to adapt, and learned learned learned, until Iā€™ve had it mapped in my head. Iā€™m still learning though, ten plus years in the future, itā€™s bizarre how big it is. In its latest incarnations, it has seriously become my favorite imperative language so far, and Iā€™ve been coding since 1987.

Oh, Iā€™ve been a VB guy in the late 90ā€™s. I loved it, but then I fell in love with C syntax all of a sudden. Iā€™m thankful for the VB chapter in my life, because I learned a lot from itā€™s offline MSDN docs, pre-internet.

If it helps, my focus in code isnā€™t that much in getting things done, though Iā€™m an engineer at heart, then a demo coder next. I like my code elegant, beautiful, and clever all at once, in that respective order, the latter being sacrificed the most (when a sacrifice has to be made). And itā€™s a useful habit of mine, not because Iā€™m popular at companies (Iā€™m clearly not), but because I can stress test a language by trying to redesign the codebase until it resembles poetry. The language isnā€™t potent if it canā€™t look like poetry, at least in places. C# is 10/10 in this regard, even surpassing ActionScript 3 which is probably still the most expressive OOP language I have ever worked with.

Though it is necessary to distinguish such poetry from the clockwork code and the API code. These two typically require a different approach, because you simply have to make compromises either for performance or maintainability. Clockwork is very similar to C++ in C#, and I missed being able to go low in some higher languages, here youā€™re enabled to overload your operators, you can access memory directly, you can fiddle with how things will get compiled, optimize your calls, optimize access by reference, itā€™s not only about applying the organizational structure and building patterns, you can truly design something really performant. So it really pays knowing what exactly is going on with this language.

You know i.e. you can set your goals to try and triangulate a patch of hundreds of sampled points in a 50 ms budget. And you can really pursue this goal and do all kinds of things, not just a straight triangulation, but ray casting, edge flipping, mesh relaxation, and there is still room to shave it more and more, and do marvelous things within the budget. The only other language capable of this, in my experience, is C/C++, but imo itā€™s simply too wild to be saddled by a lone cowboy. This lets me get things done.

I figured it out and it was pretty simple. I used random values when I create the list in the first place. Works great.