1

我有一个实现 IDisposable 接口的类。我正在使用网络客户端使用 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

4 回答 4

8

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

  1. 把它放在一个using块中
  2. 将它包装在一个也正确实现 IDisposable 的类中,并在释放这个新类时释放它。您现在希望新类的所有实例都是用using块创建的。

请注意,我说的是“或”,而不是“和”。做一个或另一个,但不要两者都做。

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

于 2009-05-18T02:56:51.697 回答
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();
        }               
    }
}
于 2009-05-18T02:53:11.690 回答
3

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

有关 using 语句的更多信息,请参阅“ using 语句(C# 参考) ”。

于 2009-05-18T02:58:51.677 回答
3

其他答案是正确的,但他们都错过了一个事实,即您在不应该声明终结器时声明了终结器。

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

  • 避免使类型可终结。
  • 如果类型负责释放没有自己的终结器的非托管资源,请务必使类型可终结

所以 rpetrich 的编辑答案是正确的,提供编辑权限的人会删除终结器。

于 2010-04-06T02:58:06.363 回答