-1

I have collection:

public class myList : List<myClass> { }

And do:

foreach (myClass obj in myList) {
    //...
    if (some_condition) {
        myList.Add(newObj); }
    //...
}

So before 2 iteration i get error like: collection was changed. Obviously problem is in myList.Add(newObj);.

How can i organize this loop to avoid errors? Keep in mind: i can add some elements to list but never remove.

I can just use for loop with iterator. But in this case my code will look a bit worse. Maybe here is some better solution?

D4C
  • 149
  • 7
  • Can we see the actual code? –  Mar 17 '15 at 13:14
  • 2
    If you are modifying the list as you go, you have to iterate by index. However you might want to rethink your implementation here because this is generally dangerous/bad practice and any newly added items would not be hit during the loop. – Jason Faulkner Mar 17 '15 at 13:14
  • @JasonFaulkner It depends on for loop condition if condition says `i < collection.Length` then he would also iterate over newly added elements. Eventhough you are right it is bad practise anyway. – Jenish Rabadiya Mar 17 '15 at 13:16
  • @JenishRabadiya - You are right. My understanding is he wanted to use a `for` loop. – Jason Faulkner Mar 17 '15 at 13:17
  • 4
    Depending on the situation, you might want to consider creating a second list for new items. Then, do a myList.AddRange(newList) after the foreach has completed. – James R. Mar 17 '15 at 13:18
  • 1
    Think about it, what does iterating over a changing collection mean? It's up to your imagination. What I do is to snap shot the collection to an array and iterate over the snapshot (of course yours may be too large, but you give no details). If that iteration requires a change to the collection, I change the collection not the snapshot. – Les Mar 17 '15 at 13:18
  • @JamesR. But if new items should be processed also, and in their turn can cause the creation of even more items, then some recursive solution will be required. In any case such collection manipulation is a very strange requirement. – Eugene Podskal Mar 17 '15 at 13:20
  • @EugenePodskal, that's why I said "depending on the situation" :). It's not entirely clear from the question what the intended behavior should be. – James R. Mar 17 '15 at 13:22

2 Answers2

7

you can force the duplication of the collection --> a new iterator will be created on the duplicated collection. the easiest way to duplicate the collection is the extension method ToArray() which creates a generic array out of the list. This will not copy the objects but only the references to them.

foreach(myClass obj in myList.ToArray())
{
      ...
}

this means that you will always loop over all items in the collection before any changes happened! no added, no removed.

fixagon
  • 5,506
  • 22
  • 26
  • 1
    you can also modify the myList within the foreach loop now, because you are iterating over a copy – Les Mar 17 '15 at 13:23
0

You can use an index to traverse the list rather than foreach, and then you can add items to the list as you traverse it.

For example:

var list = Enumerable.Range(1, 10).ToList(); // 1 , 2, 3, ..., 9, 10

// For each odd number in the list, add that number * 100 to the list.

for (int i = 0, n = list.Count; i < n ; ++i)
{
    if ((list[i] & 1) != 0)      // Number is Odd?
        list.Add(list[i] * 100); // Append 100*number
}

foreach (int n in list)
    Console.WriteLine(n);
Matthew Watson
  • 104,400
  • 10
  • 158
  • 276