Reputation: 22486
I have a class that implements the IDisposable interface. I am using a webclient to download some data using the AsyncDownloadString.
I am wondering have I correctly declared my event handlers in the constructor and within the using statement of the web client? And is this correct way to remove the event handlers in the Dispose method?
Overrule is this the correct way to use the IDisposable interface?
public class Balance : IDisposable
{
//Constructor
WebClient wc;
public Balance()
{
using (wc = new WebClient())
{
//Create event handler for the progress changed and download completed events
wc.DownloadProgressChanged += new DownloadProgressChangedEventHandler(wc_DownloadProgressChanged);
wc.DownloadStringCompleted += new DownloadStringCompletedEventHandler(wc_DownloadStringCompleted);
}
}
~Balance()
{
this.Dispose(false);
}
//Get the current balance for the user that is logged in.
//If the balance returned from the server is NULL display error to the user.
//Null could occur if the DB has been stopped or the server is down.
public void GetBalance(string sipUsername)
{
//Remove the underscore ( _ ) from the username, as this is not needed to get the balance.
sipUsername = sipUsername.Remove(0, 1);
string strURL =
string.Format("https://www.xxxxxxx.com",
sipUsername);
//Download only when the webclient is not busy.
if (!wc.IsBusy)
{
// Download the current balance.
wc.DownloadStringAsync(new Uri(strURL));
}
else
{
Console.Write("Busy please try again");
}
}
//return and display the balance after the download has fully completed
void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
//Pass the result to the event handler
}
//Dispose of the balance object
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
//Remove the event handlers
private bool isDisposed = false;
private void Dispose(bool disposing)
{
if (!this.isDisposed)
{
if (disposing)
{
wc.DownloadProgressChanged -= new DownloadProgressChangedEventHandler(wc_DownloadProgressChanged);
wc.DownloadStringCompleted -= new DownloadStringCompletedEventHandler(wc_DownloadStringCompleted);
wc.Dispose();
}
isDisposed = true;
}
}
}
Upvotes: 1
Views: 7746
Reputation: 415600
There are two correct ways to use an IDisposable object:
using
blockusing
blocks.Note that I said "or", not "and". Do one or the other, but not both.
Here, when you create your WebClient instance with a using
block in the constructor, you dispose it before you ever have a chance to use it anywhere else. You should do just option two, in this case.
Upvotes: 8
Reputation: 2949
The other answers are correct but they have all missed the fact that you are declaring a finalizer when you shouldn't.
From the .Net Framework Design Guidelines (page 258):
So the edited answer of rpetrich is correct, providing someone with edit privileges deletes the finalizer.
Upvotes: 3
Reputation: 44312
Since you have declared wc inside of a using statement you should not be used outside of that. So I would guess that your calls using wc inside of the GetBalance throw exceptions. You should remove the using block from the Balance contstructor.
See "using statement (C# Reference)" for more info on the using statement.
Upvotes: 3
Reputation: 32316
That is mostly correct except wc
is being disposed twice and GetBalance
will always be using wc
after it's disposed!
Edit: a version with that correction:
public class Balance : IDisposable
{
//Constructor
WebClient wc;
public Balance()
{
wc = new WebClient();
//Create event handler for the progress changed and download completed events
try {
wc.DownloadProgressChanged += new DownloadProgressChangedEventHandler(wc_DownloadProgressChanged);
wc.DownloadStringCompleted += new DownloadStringCompletedEventHandler(wc_DownloadStringCompleted);
} catch {
wc.Dispose();
throw;
}
}
~Balance()
{
this.Dispose(false);
}
//Get the current balance for the user that is logged in.
//If the balance returned from the server is NULL display error to the user.
//Null could occur if the DB has been stopped or the server is down.
public void GetBalance(string sipUsername)
{
//Remove the underscore ( _ ) from the username, as this is not needed to get the balance.
sipUsername = sipUsername.Remove(0, 1);
string strURL =
string.Format("https://www.xxxxxxx.com",
sipUsername);
//Download only when the webclient is not busy.
if (!wc.IsBusy)
{
// Download the current balance.
wc.DownloadStringAsync(new Uri(strURL));
}
else
{
Console.Write("Busy please try again");
}
}
//return and display the balance after the download has fully completed
void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
//Pass the result to the event handler
}
private bool isDisposed = false;
//Dispose of the balance object
public void Dispose()
{
if (!isDisposed)
Dispose(true);
GC.SuppressFinalize(this);
}
//Remove the event handlers
private void Dispose(bool disposing)
{
isDisposed = true;
if (disposing)
{
wc.DownloadProgressChanged -= new DownloadProgressChangedEventHandler(wc_DownloadProgressChanged);
wc.DownloadStringCompleted -= new DownloadStringCompletedEventHandler(wc_DownloadStringCompleted);
wc.Dispose();
}
}
}
Upvotes: 7