这对于使用IDisposable处理对象是否正确

时间:2009-05-18 02:48:56

标签: c# idisposable

我有一个实现IDisposable接口的类。我正在使用webclient使用AsyncDownloadString下载一些数据。

我想知道我是否在构造函数中和Web客户端的using语句中正确声明了我的事件处理程序?这是在Dispose方法中删除事件处理程序的正确方法吗?

否决这是使用IDisposable接口的正确方法吗?

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;
        }
    }
}

4 个答案:

答案 0 :(得分:8)

使用IDisposable对象有两种正确的方法:

  1. 将其放入using区块中
  2. 将它包装在同样正确实现IDisposable的类中,并在处理此新类时将其处理掉。您现在希望使用using块创建新类的所有实例。
  3. 请注意,我说“或”,而不是“和”。做一个或另一个,但不是两个。

    在这里,当您在构造函数中使用using块创建WebClient实例时,在有机会在其他任何地方使用它之前将其处置掉。在这种情况下,您应该只选择选项二。

答案 1 :(得分:7)

除了wc被处理两次以外GetBalance处置完毕后wc将永远使用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(); } } } ,这大部分都是正确的!

编辑:具有该更正的版本:

{{1}}

答案 2 :(得分:3)

由于您已在using语句中声明了wc,因此不应在其外部使用。所以我猜你在GetBalance中使用wc的调用会引发异常。 您应该从Balance contstructor中删除using块。

有关using语句的详细信息,请参阅“using statement (C# Reference)”。

答案 3 :(得分:3)

其他答案是正确的,但他们都错过了你不应该宣布终结者的事实。

来自.Net框架设计指南(第258页):

  • 避免使类型最终化。
  • 如果类型负责释放没有自己的终结器的非托管资源,请将类型设置为finalizable。

所以rpetrich的编辑答案是正确的,如果某人有编辑权限,则删除终结者。