2010-03-30 15 views
45

Wäre das eine gute Möglichkeit, einen BackGroundWorker zu entsorgen? Ich bin mir nicht sicher, ob es notwendig ist, die Ereignisse vor dem Aufruf von .Dispose() zu entfernen. Auch Aufruf von .Dispose() innerhalb des RunWorkerCompleted-Delegat in Ordnung zu tun?Richtiger Weg, einen BackGroundWorker zu entsorgen

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(); 
} 
+0

ist dies ein Hintergrundarbeiter auf einem Formular? –

+0

Ja ist es, obwohl ich die BGW programmgesteuert erstellt habe, anstatt sie auf das Formular im Designer zu legen. Wie gezeigt, wird die BGW erstellt, wenn ich den Thread ausführen möchte. Die Idee war, jedes Mal, wenn der Thread aufgerufen wurde, eine andere BGW zu erstellen und sie nach Abschluss zu entfernen. – galford13x

Antwort

67

BackgroundWorker leitet sich von Component ab. Component implementiert die IDisposable-Schnittstelle. Dies wiederum bewirkt, dass BackgroundWorker die Dispose() -Methode erbt.

Das Ableiten von Component ist eine Annehmlichkeit für Windows Forms-Programmierer, sie können eine BGW aus der Toolbox auf ein Formular löschen. Komponenten haben im Allgemeinen etwas zu veräußern. Der Windows Forms-Designer erledigt dies automatisch. Suchen Sie in der Datei Designer.cs nach einem Formular für das Feld "Komponenten". Die automatisch generierte Dispose() -Methode ruft die Dispose() -Methode für alle Komponenten auf.

Allerdings hat BackgroundWorker eigentlich kein Mitglied, das entsorgt werden muss. Es überschreibt Dispose() nicht. Die Basisimplementierung, Component.Dispose(), stellt nur sicher, dass die Komponente aus der Sammlung "components" entfernt wird. Und hebe das Disposed-Ereignis auf. Verfügt aber ansonsten nichts.

Lange Rede, kurzer Sinn: Wenn Sie eine BGW auf ein Formular fallen lassen, dann wird alles automatisch erledigt, Sie müssen nicht helfen. Wenn Sie es nicht in ein Formular eingefügt haben, ist es kein Element in einer Komponentensammlung und es muss nichts getan werden.

Sie müssen nicht Dispose() aufrufen.

+6

Persönlich mag ich die Politik des Aufrufens 'Dispose' befolgen, falls vorhanden, falls sich die Implementierung der Klasse tatsächlich ändert ... –

+3

Daran kann ich nicht streiten. Aber ziehe es vor, immer zu denken: "Welche Art von Objekt könnte von einer Klasse umhüllt werden, die entsorgt werden müsste?" Und sieh es dir an. Ich habe Probleme, Code zu schreiben, der keinen Sinn macht und nicht die Vorstellung, dass es irgendwann einen Sinn ergeben wird. Es funktioniert auch andersherum: Die Klasse Thread hat wirklich Einwegobjekte, implementiert aber IDisposable nicht. Jedem sein eigenes. –

+1

Nur so verstehe ich. Eine BGW muss nicht entsorgt werden, da sie nichts zu entsorgen hat? Ich hatte irgendwann gelesen, dass, wenn Ereignisse nicht entfernt werden, sie weiter abhängen können, wenn sie freigegebene Ressourcen verhindern, wenn ein Objekt, das auf ihnen beruht, entsorgt wird. Ist das niemals der Fall? – galford13x

0

Ja, das scheint richtig. Natürlich werden Einwegobjekte besser mit using Blöcken behandelt, aber Sie haben diese Option hier nicht.

Normalerweise erstelle ich meine Hintergrund-Handler mit Formular-Lebenszeiten, wiederverwenden sie und lassen Sie den Designer-Code Umgang mit Formular schließen. Weniger zum Nachdenken.

+0

So habe ich es in der Vergangenheit immer gemacht. Obwohl mir nicht bewusst war, dass das Zurücksetzen eines BackGroundWorker in einem WinForm während der Entwurfszeit die BGW zu der Liste des Objekts hinzugefügt hat, das beim Ablegen des Formulars Disposed wäre. Ich hatte die BGW in der Regel programmatisch erstellt. – galford13x

0

Wenn es auf einem „WinForms“ Form ist der Behälter lassen sich darum kümmern (siehe die erzeugte Dispose Code in der Datei Form.Designer.xyz)

In der Praxis habe ich festgestellt, dass Sie ein erstellen müssen können Instanz des Containers und fügen Sie den Worker (oder einen anderen Companent) hinzu, wenn jemand einen offizielleren Weg kennt, dies zu tun!

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

} 
13

spät zum Spiel, aber ich lief nur ein Szenario über zu Ihrer Frage, dass ich dachte, dass ich teilen. Wenn Sie Ihren Worker auf Klassenebene erstellen und ihn bei aufeinanderfolgenden Vorgängen wiederverwenden, ohne die Anwendung zu schließen, werden die Ereignisse bei jeder nachfolgenden Ausführung erhöht und mehrfach ausgeführt, wenn Sie die Ereignisse nach Abschluss nicht entfernen.

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

Ohne die über mein DoWork Feuer einmal das erste Mal, zweimal das zweite Mal, etc. Dies ist wahrscheinlich ein Kinderspiel für die meisten, aber es hat mir ein bisschen, um es herauszufinden, hoffentlich diesen Willen hilf jemandem anderen.

+0

Können Sie einen detaillierteren Code für Ihr Szenario angeben? Ich benutze BW und das (soweit ich weiß) passierte mir nie –

+0

Ohne ein komplettes Beispiel zu schreiben gibt es nicht viel mehr zu erklären, aber ich werde es versuchen. Wenn "worker" außerhalb der Methoden definiert ist, die es verwenden (d. h. global auf Anwendungsebene), aber Sie diesen Worker innerhalb einer dieser Methoden subskribieren, ohne die Subskription bei jeder Iteration zu entfernen, werden Subskriptionen weiterhin exponentiell wachsen. – Paul

+0

Mein Verständnis ist, dass Sie die Ereignisse in einer Methode abonnieren, die mehrmals aufgerufen wird. Wenn ja: ja, natürlich; Wenn nicht, fasse ich es immer noch nicht. –

1

worker.Dispose() ist nicht erforderlich, da Dispose() automatisch aufgerufen wird. Bevor Sie jedoch das Objekt entfernen, müssen Sie alle Ereignisbehandlungsroutinen entfernen.

Diese article informiert uns darüber.

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

Wenn es einmal wahr war, dass der Artikel das Entfernen von Event-Handlern erwähnt, ist es nicht mehr so. In allen Versionen des verlinkten Artikels werden Ereignisse nicht erwähnt. – kbrimington

Verwandte Themen