8

Let's suppose I have this function that can be called several times from the main thread. Every time this is called, I create a WebClient object to download some data asynchronously.

My question... is this safe to do? Is the WebClient object released after the event is called? I wouldn't like to keep allocating memory if it is not going to be freed automatically.

My application is for WP7 with Silverlight.

Thanks!

void DownloadData(string cURL)
{
    WebClient webClient = new WebClient();
    webClient.DownloadStringCompleted +=
       new System.Net.DownloadStringCompletedEventHandler(
            webClient_DownloadStringCompleted);
    webClient.DownloadStringAsync(new Uri(cURL));
}

static void webClient_DownloadStringCompleted(object sender,
                      System.Net.DownloadStringCompletedEventArgs e)
{
    ...
}
sharptooth
  • 167,383
  • 100
  • 513
  • 979
LEM
  • 825
  • 6
  • 16
  • 31
  • It is not clear whether any live object is holding a reference to your WebClient object. DownloadStringAsync is probably setting something up to do that, but I would be more worried about it getting garbage collected too early rather than too late! :) – Jeffrey L Whitledge May 19 '11 at 18:51

4 Answers4

4

Instead of manually disposing of WebClient you could just put it in a using block.

using (WebClient webClient = new WebClient())
{
    // Your business in here...
}
kbo4sho88
  • 175
  • 7
4

The SilverLight version of WebClient doesn't implement IDisposable. You are doing it right - webClient will be automatically garbage collected when the time comes.

Greg
  • 23,155
  • 11
  • 57
  • 79
1

I see 2 problems. First of all, webclient isnt disposed in all possible situations, secondly a reference to WebClient will be maintained since you never unsubscribe the event.

I think this comes close to it (still not perfect though, think about ThreadAborted):

void DownloadData(string cURL) 
        {
            WebClient webClient = new WebClient();

            try
            {
                webClient.DownloadStringCompleted += new System.Net.DownloadStringCompletedEventHandler(webClient_DownloadStringCompleted);
                webClient.DownloadStringAsync(new Uri(cURL));
            }
            catch
            {
                webClient.Dispose();
                throw;
            }
        }

        static void webClient_DownloadStringCompleted(object sender, System.Net.DownloadStringCompletedEventArgs e)
        {
            WebClient webClient = (WebClient)sender;

            webClient.DownloadStringCompleted -= webClient_DownloadStringCompleted;

            try
            {

            }
            finally
            {
                webClient.Dispose();
            }
        }
Polity
  • 14,734
  • 2
  • 40
  • 40
  • Sorry, I should have mentioned it. I'm using Silverlight for WP7, so the Dispose() method is not available. – LEM May 19 '11 at 18:37
  • 2
    When an event is subscribed to, isn't it observed (`WebClient`) that retains a reference to the observer (`webClient_DownloadStringCompleted`)? If so, then there wouldn't be any need to unsubscribe the event. – Greg May 19 '11 at 18:39
  • @Moonlit: Fair enough, then we can simplify the code by not caring about the dispose at all – Polity May 19 '11 at 18:41
-4

WebClient does not implement the iDisposable interface so there is nothing special that needs to be done to allow for proper garbage collection. When the CLR detects that there are no current references to the object, it will be scheduled for garbage collection. Of course you don't know just when that will occur so the memory may or may not (most likely not) be freed up immediately.

Bueller
  • 2,336
  • 17
  • 11
  • 7
    Actually, it does implement Dispose since it inherits from Component ( http://msdn.microsoft.com/en-us/library/system.componentmodel.component.aspx ) – Polity May 19 '11 at 18:29
  • 1
    I retract my statements. You are in fact correct. Apologize to any for any confusion I may have caused. – Bueller May 19 '11 at 18:38
  • 1
    Sorry I didn't mention it. I'm using Silverlight on WP7 so the Dispose method is indeed NOT implemented. – LEM May 19 '11 at 18:39
  • Even if WebClient did inherit a Dispose method from Component, the fact that it does so explicity rather than implicitly is a clue that maybe Dispose does not need to be called on this object. I think this is actually the correct answer. – Jeffrey L Whitledge May 19 '11 at 18:47
  • 2
    @Jeffrey: I always like working with both the idea that making assumptions is dangerous and with the idea that making exceptions should be exceptional. which translates in if there is a dispose method, then call it. Besides, who's to say its base class actually implementing Dispose doesnt have to be disposed? – Polity May 19 '11 at 18:56
  • @Polity - That’s why I said “maybe” and “I think”. I expect further research should be done to decide with certainty. (The Silverlight implementation is another clue that maybe it’s not necessary.) I also follow the practice that if there is a dispose method then call it, but only if it is among the members of the variable's type. (Also, if there is a Close method, then I will dispose as well.) Shadowy kinda-there-kinda-not Dispose methods require further research. – Jeffrey L Whitledge May 19 '11 at 19:10