2

I currently have 4 Timers adding objects to a List but as soon as they get out of the WinForms Control they should be deleted.

I've Tried this :

foreach (Auto a in autoListe)
{
    if (a.X > 550 || a.X < -50 || a.Y > 550 || a.Y < -50)
    {
        autoListe.Remove(a);
    }
}

But when an Object leaves the Control this gives out an Exception due to the List being used to add Cars at the same time.

So now I'm not sure how to remove Object since the adding of the Objects needs to be constant

klashar
  • 2,519
  • 2
  • 28
  • 38
D.Mendes
  • 159
  • 1
  • 11

4 Answers4

1

You cannot modify a collection while iterating. You have to store your cars that you want to remove and then remove them from the original list.

var autosDieGeloeschtWerdenSollen = new List<Auto>();
foreach (Auto a in autoListe)
{
    if (a.X > 550 || a.X < -50 || a.Y > 550 || a.Y < -50)
    {
        autosDieGeloeschtWerdenSollen.Add(a);
    }
}
autoListe.RemoveRange(autosDieGeloeschtWerdenSollen);

If autoliste is a List<Auto> you can also use tho following:

autoListe.RemoveAll(a => a.X > 550 || a.X < -50 || a.Y > 550 || a.Y < -50);

You can also use a backwards for-loop but I would not recommend that as it is hard to understand. This also only works if your Collection is a List<Auto>.

for (int i = autoListe.Count - 1; i >= 0; i--)
{
    var a = autoListe[i];

    if (a.X > 550 || a.X < -50 || a.Y > 550 || a.Y < -50)
    {
      autoListe.RemoveAt(i);
    }
}
wertzui
  • 5,148
  • 3
  • 31
  • 51
  • just remove your backwards for loop sentence, didn't get what you mean otherwise i dont see why someone marked this down. – Seabizkit Feb 27 '17 at 07:32
0

You cannot modify a collection while iterating through it. Implementation of the list is such that it keeps private version number inside of it, and every change you make, like calling the Remove() method increments the content version number.

Moving to the next element (which is done by the foreach loop) checks whether the version number is the same as when the enumerator was created. If not, exception is thrown.

If you want to purge items based on the criterion, then you have to construct the new list out of the first one, which would then not contain the unwanted elements:

autoListe = 
    autoListe
        .Where(a => !(a.X > 550 || a.X < -50 || a.Y > 550 || a.Y < -50))
        .ToList();

You may also use RemoveAt() method of the list in the loop which doesn't construct the enumerator, but that is far more complicated than this.

Zoran Horvat
  • 10,924
  • 3
  • 31
  • 43
  • If yo use a for loop you can, see http://stackoverflow.com/questions/1582285/how-to-remove-elements-from-a-generic-list-while-iterating-over-it – apomene Feb 24 '17 at 14:06
  • Because you haven't constructed the enumerator. However, that solution may turn tremendously inefficient. – Zoran Horvat Feb 24 '17 at 14:07
0
autoListe.RemoveAll(a => a.X > 550 || a.X < -50 || a.Y > 550 || a.Y < -50);

or

for (int i = autoListe.Count - 1; i >= 0; i--)
{
    var a = autoListe[i];

    if (a.X > 550 || a.X < -50 || a.Y > 550 || a.Y < -50)
    {
      autoListe.RemoveAt(i);
    }
}
hyankov
  • 4,049
  • 1
  • 29
  • 46
0

You can use the RemoveAll() function to remove the cars:

autoListe.RemoveAll(x => x.Auto > 550 || x.Auto < -50 || x.Auto > 550 || x.Auto < -50);
Ethilium
  • 1,224
  • 1
  • 14
  • 20
  • 1
    The RemoveAll is a great and simple method, but it has nothing to do with Linq. However RemoveAll and Linq both deal with Lambdas. – wertzui Feb 24 '17 at 14:16