B.K. B.K. - 2 months ago 13
C# Question

Object disposal and garbage collection prior to event triggering

A piece of code was brought up by someone I was talking to:

private void DownloadInformation(string id)
{
using (WebClient wc = new WebClient())
{
wc.DownloadStringCompleted +=
new DownloadStringCompletedEventHandler(DownloadStringCompleted);
wc.DownloadStringAsync(new Uri("http://www.fake.com/" + id));
}
}


The above is a simplified version of this:

enter image description here

(I have the author's permission to post the image.)

What bothers me about that code is that an event handler is attached,
DownloadStringAsync()
is called and then the
using
block ends, which calls
Dispose()
on
WebClient
. Is there anything that will prevent
WebClient
from being disposed off by
using
and even garbage collected prior to
DownloadStringAsync()
completing and
DownloadStringCompleted
event triggering?

There's a newer method,
DownloadStringTaskAsync()
, which I would think to use in conjunction with
await
:

private async void DownloadInformation(string id)
{
using (WebClient wc = new WebClient())
{
wc.DownloadStringCompleted +=
new DownloadStringCompletedEventHandler(DownloadStringCompleted);
await wc.DownloadStringTaskAsync(new Uri("http://www.fake.com/" + id));
}
}


However, even then... I would basically be betting that event triggers and handler gets called before the
WebClient
gets disposed off.

Am I misunderstanding the life cycle of
WebClient
in this scenario or is this a terrible code design?

Answer

The WebClient doesn't implement IDisposable, its base class Component does.

The Component class Disposes any eventhandlers that are registered with its Events property but the WebClient doesn't use that property.

Calling Dispose on the WebClient doesn't have an effect on any state managed by the webclient.

The actual handling of internal resources is done in the private method DownloadBits and an internal class DownloadBitsState.

So the code you show is up to now free of any effects due to releasing resources too early. That is however caused by an implementation detail. Those might change in the future.

Due to the framework keeping track of pending callbacks you don't have to worry about premature garbage collection as well, as is explained in this answer, kindly provided by Alexei Levenkov.

Comments