Code confusion - why does one work, but not the other?
Asked Answered
K

1

7

Note: This already works fine, but I'm trying to understand Why it works this way, but not the other.

I have a WinForm (C#) with dynamically put images, like so: enter image description here

Now if you click the 'Napred' button, these images should be deleted (among other things), for which I originally used:

foreach(Control ctrl in Controls)
    if(ctrl is PictureBox) ctrl.Dispose();

or

for(int i = 0; i < Controls.Count; i++)
    if(Controls[i] is PictureBox) Controls[i].Dispose();

Now if I run this, I get:

enter image description here

But if I just change the for statement to send it backwards, it works?

for(int i = Controls.Count - 1; i >= 0; i--)
    if(Controls[i] is PictureBox) Controls[i].Dispose();

(I'm not going to upload another image, but it deletes all of the elements (I only get the buttons left in the end))

Can someone enlighten me why one works, but not the other?

EDIT: I'm using VS2015 community edition on Windows 10 if it's a debugging error(?)

Kingfish answered 3/12, 2015 at 9:17 Comment(5)
If you have an array of 10 items and then delete Item1, Item2 will become new Item1 and you will have 9 items remaining. Standard method of disposing of array items is to step through it backwards.Aikido
Might be of interest for other approaches: #7341257Terrijo
Why don't you use Remove method?Stag
@SergiiZhevzhyk I did, pretty much the same result, but I've read elsewhere on SO that Remove() doesn't properly dispose of the element (memory-wise) and that this is a better solution.Kingfish
@NemanjaT I totally agree that all resources should be properly disposed. I would probably remove the picture from the collection and then dispose it.Stag
N
12

You're trying to change the list you're iterating over, which of course will change the indexes of this list so what was at index 1 is now at index 0.

By removing from the end of the array (I.e in your reverse), the previous indexes will always be the same.

Its also important to note as stated in Matthew Watson's comment:

Control.Dispose() is special and will remove the control from a parent container's Controls list.

This isn't default behavour by most Dispose methods so therefore you won't always find this behaviour when using Dispose

Nymphet answered 3/12, 2015 at 9:23 Comment(5)
I understand, that's why every 2nd element is being deleted. Thanks for clearing this up! It didn't cross my mind at all!Kingfish
I think you should be clear about how he's changing the list over which he is iterating, because just from inspecting the code he is not removing items from the list directly. The answer is that Control.Dispose() is special and will remove the control from a parent container's Controls list.Kerge
@MatthewWatson - Very true, I was trying to keep this generic in reference to lists themselvesNymphet
But it would normally be fine to iterate in that way, disposing items in a list in order, since it wouldn't change the indices of the items in the list. It is extremely relevant that it is the Controls property that is being iterated. Just calling Dispose() on an item in a list does NOT generally change the list itself.Kerge
@MatthewWatson - I've included part of your comment in my answer now, I was trying to find a correct reference to this in msdn or developersource but wasn't able to. Hope this is ok!Nymphet

© 2022 - 2024 — McMap. All rights reserved.