user2544563
user2544563

Reputation: 79

Removing items from a list when a condition is met

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

Answers (3)

Patashu
Patashu

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

nmclean
nmclean

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

keyboardP
keyboardP

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

Related Questions