1

IDisposable インターフェイスを実装するクラスがあります。AsyncDownloadString を使用してデータをダウンロードするために Web クライアントを使用しています。

コンストラクターと 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オブジェクトを使用する正しい方法は2つあります。

  1. usingブロックに入れる
    または
  2. IDisposableも正しく実装しているクラスでラップし、この新しいクラスが破棄されたときに破棄します。これで、新しいクラスのすべてのインスタンスがusingブロックで作成されることが期待されます。

「and」ではなく「or」と言ったことに注意してください。どちらか一方を実行しますが、両方を実行することはできません。

ここで、コンストラクター内のブロックを使用してWebClientインスタンスを作成する場合、using他の場所で使用する前に、それを破棄します。この場合、オプション2だけを実行する必要があります。

于 2009-05-18T02:56:51.697 に答える
7

wcこれは、 2回廃棄され、廃棄後に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を使用した呼び出しは、例外をスローすると思います。Balancecontstructorからusingブロックを削除する必要があります。

usingステートメントの詳細については、「usingステートメント(C#リファレンス)」を参照してください。

于 2009-05-18T02:58:51.677 に答える
3

他の答えは正しいですが、ファイナライザーを宣言すべきではないときに宣言しているという事実をすべて見逃しています。

.Net Framework 設計ガイドライン (258 ページ) から:

  • タイプをファイナライズ可能にしないでください。
  • 型が独自のファイナライザーを持たないアンマネージ リソースの解放を担当する場合は、型をファイナライズ可能にします。

したがって、rpetrich の編集された回答は正しいため、誰かに編集権限を与えると、ファイナライザーが削除されます。

于 2010-04-06T02:58:06.363 に答える