web-dev-qa-db-ja.com

BackGroundWorkerを廃棄する適切な方法

これはBackGroundWorkerを処分する適切な方法でしょうか? .Dispose()を呼び出す前にイベントを削除する必要があるかどうかはわかりません。 RunWorkerCompletedデリゲート内で.Dispose()を呼び出すこともできますか?

public void RunProcessAsync(DateTime dumpDate)
{
    BackgroundWorker worker = new BackgroundWorker();
    worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
    worker.DoWork += new DoWorkEventHandler(worker_DoWork);
    worker.RunWorkerAsync(dumpDate);
}

void worker_DoWork(object sender, DoWorkEventArgs e)
{
    // Do Work here
}

void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    BackgroundWorker worker = sender as BackgroundWorker;
    worker.RunWorkerCompleted -= new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
    worker.DoWork -= new DoWorkEventHandler(worker_DoWork);
    worker.Dispose();
}
48
galford13x

BackgroundWorkerはComponentから派生します。コンポーネントはIDisposableインターフェイスを実装します。これにより、BackgroundWorkerはDispose()メソッドを継承します。

コンポーネントから派生することはWindowsフォームプログラマにとって便利であり、ツールボックスからフォームにBGWをドロップできます。一般に、コンポーネントには廃棄するものがある可能性があります。 Windows Formsデザイナはこれを自動的に処理し、Designer.csファイルで「コンポーネント」フィールドのフォームを探します。その自動生成されたDispose()メソッドは、すべてのコンポーネントに対してDispose()メソッドを呼び出します。

ただし、BackgroundWorkerには実際に破棄を必要とするメンバーはいません。 Dispose()をオーバーライドしません。その基本実装であるComponent.Dispose()は、コンポーネントが「コンポーネント」コレクションから削除されることのみを確認します。そして、Disposedイベントを発生させます。しかし、そうでなければ何も処分しません。

簡単に言えば、フォームにBGWをドロップした場合、すべてが自動的に処理されるため、支援する必要はありません。フォームにドロップしなかった場合、コンポーネントコレクションの要素ではないため、何もする必要はありません。

Dispose()を呼び出す必要はありません

71
Hans Passant

ゲームに遅れたが、あなたの質問に関連するシナリオに出くわした。クラスレベルでワーカーを作成し、アプリを閉じずに連続した操作で再利用する場合、完了後にイベントを削除しないと、連続する実行ごとにインクリメントして複数回実行されます。

worker.RunWorkerCompleted -= new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
worker.DoWork -= new DoWorkEventHandler(worker_DoWork);

上記がなければ、DoWorkは最初に1回、2回目に2回などを起動します。これはおそらくほとんどの場合簡単なことですが、それを理解するには少し時間がかかりました。

13
Paul

worker.Dispose()は自動的に呼び出されるため、Dispose()は不要です。ただし、オブジェクトを破棄する前に、すべてのイベントハンドラーを削除する必要があります。

この 記事 は、これについて通知します。

worker.RunWorkerCompleted -= new RunWorkerCompletedEventHandle(worker_RunWorkerCompleted);
worker.DoWork -= new DoWorkEventHandler(worker_DoWork);
1
AlexN

はい、これは適切なようです。もちろん、使い捨てオブジェクトはusingブロックでより適切に処理されますが、ここにはそのオプションはありません。

通常、フォームライフタイムを使用してバックグラウンドハンドラを作成し、それらを再利用して、デザイナーコードがフォームを閉じるときに処理を処理できるようにします。考えることは少ない。

0

「WinForms」フォーム上にある場合、コンテナが処理します(Form.Designer.xyzファイルで生成されたDisposeコードを参照)

実際には、コンテナのインスタンスを作成し、ワーカー(またはその他のコンポーネント)を追加する必要があるかもしれないことがわかりました。

PK :-)

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        // watch the disposed event....
        backgroundWorker1.Disposed += new EventHandler(backgroundWorker1_Disposed);

        // try with and without the following lines
        components = new Container();
        components.Add(backgroundWorker1);
    }

    void backgroundWorker1_Disposed(object sender, EventArgs e)
    {
        Debug.WriteLine("backgroundWorker1_Disposed");
    }

//... from the Designer.xyz file ...

    /// <summary>
    /// Clean up any resources being used.
    /// </summary>
    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }

}
0
Paul Kohler