Reputation: 79
I'm writing a multi-threaded download manager where download info is managed by a class I wrote (called DownloadOperation). Downloads are held in a list (called download). I need to remove the objects from the list when a function in the class (queryCompleted) returns true but found out that elements could not be removed from lists from within a foreach
loop. What is the best way to have the same effect? I'm relatively new to C# so pardon my stupidity.
private void removeInactiveDownloads()
{
foreach (DownloadOperation dl in download)
{
if (dl.queryComplete() == true)
{
// if download is no longer in progress it is removed from the list.
download.Remove(dl);
}
}
}
Upvotes: 7
Views: 12980
Reputation: 21773
List<T>
has a method
public int RemoveAll(
Predicate<T> match
)
that removes all elements matching a predicate: http://msdn.microsoft.com/en-us/library/wdka673a.aspx
Therefore I suggest something like:
download.RemoveAll(x => x.queryComplete());
(note that == true
is not needed since .queryComplete()
already returns true or false!)
Upvotes: 16
Reputation: 7724
Patashu's answer is the best solution in general, but based on your example code I would suggest taking another approach altogether.
Are you polling the download list periodically to find the completed ones? Event subscription would probably be a better solution. Since you're new to C#, in case you didn't know the language has built-in support for this pattern: Events
A download could raise a Completed
event when it completes, which is subscribed to by the code which manages the list, something like:
private void AddDownload(DownloadOperation dl) {
download.Add(dl);
dl.Completed += (s, e) => download.Remove(dl);
}
Upvotes: 1
Reputation: 69372
Iterate backwards in a For loop instead of a Foreach loop
for(int i = download.Count; i >= 0; i--)
{
if (download[i].queryComplete())
{
// if download is no longer in progress it is removed from the list.
download.RemoveAt(i);
}
}
Upvotes: 4