问题
There is a typical collection of some class objects e.g. string
for a simplicity
IList<string> collection = new List<string>();
During the program flow some function needs to operate on the collection, process class object and depending on the result of operation remove processed class object from collection.
E.g. following example of strings if string is "failed" then remove that item
foreach (string str in collection)
{
// operate on the current class object
// if str is not valid
if (str == "failed")
collection.Remove(str);
}
By all means that leads to exception. What is the best way to loop thru all elements having ability to remove it during enumeration?
回答1:
Do an indexed for loop, but do it backwards, because when you delete members the indexes upstream get changed.
e.g, for your string collection example:
for (int i = collection.Count() - 1; i >= 0; i--)
{
// do some other stuff, then ...
if (collection[i] == "failed")
collection.RemoveAt(i);
}
NB: if you use a forward for-loop, it may appear to work at first, but it will skip an item after each remove (because of the way indexes get renumbered after a remove). So a common symptom of that bug is that removes appear to work until you get two adjacent ones. That can be quite a confusing bug. Not that its ever happened to me *cough*
回答2:
For List<> collections you can use RemoveAll.
collection.RemoveAll ( item => item == "failed" );
For generic IEnumerable<> collections you can create a new collection with the items removed.
var newList = collection.Where ( item => item != "failed" );
As it is lazily evaluated you are not actually creating two collections in memory, rather a state machine that will enumerate through the non failed items as needed.
回答3:
If the collection is a List
or Set
, you can use an indexed for
loop and perform the deletion.
来源:https://stackoverflow.com/questions/7160343/best-way-to-enumerate-collection-when-elements-may-be-deleted-during-enumeration