You can not use the IEnumerator interface (which means you can
not use a foreach statement) for this. The interface is set
up such that if the collection being enumerated changes then the next time the enumerator
attempts to move to the next element it will throw an InvalidOperationException.
This is done internally by versioning the collection. Note that insertion,
removal and updating of an item in the collection changes the version and hence
will cause the exception. If you were to change the properties of an item
in the collection this would not impact the collection. In C#, however, the
foreach loop treats the items as read-only so you can not even
modify the item.
To enumerate a list and change the contents at the same time you will have to resort
to a standard for loop. For example suppose you wanted to
remove any string in a collection of strings that started with 'S'. The following
code would do that. Notice that you must be careful how you manage the indice
to ensure that you do not access the array outside its bounds.
Collection
names = new Collection();
names.Add("Bobby");
names.Add("Billy");
names.Add("Sue");
names.Add("John");
names.Add("Sarah");
names.Add("Sheila");
names.Add("Mark");
names.Add("Paul");
names.Add("Sally");
for (int nIdx = 0; nIdx < names.Count; ++nIdx)
{
if (names[nIdx].StartsWith("S", StringComparison.OrdinalIgnoreCase))
{
//Remove it
names.RemoveAt(nIdx);
//Adjust the index
--nIdx;
};
};
The problem I have with the above code is that there is great opportunity for error
and it makes maintenance more difficult. I feel that any code that mucks with
the loop variant should be rewritten. Fortunately some languages do not even
allow it. Memory is cheap and rarely do I care
about having two copies of a list in memory at the same time. Therefore I
recommend the following approach instead. It should work in pretty much any
case that the former code would work. I find it easier to read and understand
and less error prone. Your mileage may vary.
Collection
names = new Collection();
names.Add("Bobby");
names.Add("Billy");
names.Add("Sue");
names.Add("John");
names.Add("Sarah");
names.Add("Sheila");
names.Add("Mark");
names.Add("Paul");
names.Add("Sally");
Collection
newNames = new Collection();
for (int nIdx = 0; nIdx < names.Count; ++nIdx)
{
if (!names[nIdx].StartsWith("S", StringComparison.OrdinalIgnoreCase))
newNames.Add(names[nIdx]);
};
names = newNames;