2010-03-30 4 views
45

Est-ce que ce serait une bonne façon de disposer d'un BackGroundWorker? Je ne suis pas sûr s'il est nécessaire de supprimer les événements avant d'appeler .Dispose(). Appelle également .Dispose() dans le délégué RunWorkerCompleted ok à faire?Un moyen correct d'éliminer un BackGroundWorker

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

Est-ce un travailleur d'arrière-plan sur un formulaire? –

+0

Oui c'est le cas, bien que j'ai créé le BGW par programme plutôt que de le déposer sur le formulaire dans le concepteur. Comme indiqué le BGW est créé quand je veux exécuter le fil. L'idée était de créer une BGW différente à chaque fois que le fil était appelé et de s'en débarrasser une fois terminé. – galford13x

Répondre

67

BackgroundWorker dérive de Component. Component implémente l'interface IDisposable. Cela à son tour rend BackgroundWorker hériter de la méthode Dispose(). Dériver de Component est une commodité pour les programmeurs Windows Forms, ils peuvent déposer un BGW de la boîte à outils sur un formulaire. Les composants en général sont susceptibles d'avoir quelque chose à éliminer. Le concepteur Windows Forms s'en charge automatiquement. Dans le fichier Designer.cs, recherchez un formulaire pour le champ "composants". Sa méthode Dispose() générée automatiquement appelle la méthode Dispose() pour tous les composants. Toutefois, BackgroundWorker ne possède aucun membre nécessitant une mise au rebut. Il ne remplace pas Dispose(). Son implémentation de base, Component.Dispose(), s'assure seulement que le composant est retiré de la collection "components". Et augmentez l'événement Disposed. Mais ne dispose pas autrement. Longue histoire courte: si vous avez laissé tomber un BGW sur un formulaire alors tout est pris en charge automatiquement, vous n'avez pas besoin d'aide. Si vous ne l'avez pas déposé sur un formulaire, ce n'est pas un élément dans une collection de composants et rien ne doit être fait.

Vous ne devez pas appeler Dispose().

+6

Personnellement j'aime bien suivre la politique d'appeler 'Dispose' si présent dans le cas où l'implémentation de la classe change réellement ... –

+3

Je ne peux pas me disputer avec ça. Mais préférer toujours penser: "quel genre d'objet pourrait être enveloppé par une classe qui aurait besoin de disposer?" Et jetez un oeil. J'ai de la difficulté à écrire du code qui n'a aucun sens et je n'approuve pas l'idée que cela aura du sens un jour. Cela fonctionne aussi à l'inverse: la classe Thread a vraiment des objets jetables mais n'implémente pas IDisposable. À chacun ses goûts. –

+1

Juste pour que je comprenne. Une BGW n'a pas besoin d'être éliminée puisqu'elle n'a rien à éliminer? J'avais lu quelquefois que si les événements ne sont pas supprimés, ils peuvent continuer à traîner en empêchant les ressources libérées quand un objet qui compte sur eux sont éliminés. Est-ce que ce n'est jamais le cas? – galford13x

0

Oui, cela semble correct. Bien sûr, les objets jetables sont mieux gérés avec les blocs using, mais vous n'avez pas cette option ici.

Je crée généralement mes gestionnaires d'arrière-plan avec des durées de vie de formulaire, les réutilise et laisse le code du concepteur gérer la mise au rebut sur le formulaire. Moins à penser.

+0

Voilà comment je l'ai toujours fait dans le passé. Bien que je ne me rendais pas compte que la suppression d'un BackGroundWorker sur un WinForm au moment du design ajouté le BGW à la liste des objets qui seraient éliminés lorsque le formulaire est éliminé. J'avais généralement créé le BGW par programme. – galford13x

0

S'il est sur un « WinForms » Formulaire laisser le récipient prendre soin (voir le code Dispose généré dans le fichier Form.Designer.xyz)

Dans la pratique, j'ai trouvé que vous devrez peut-être créer un exemple du conteneur et ajouter le travailleur (ou autre compagnon) à celui-ci, si quelqu'un sait une façon plus officielle de le faire crier !!

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

tard pour le jeu, mais je suis tombé sur un scénario lié à votre question que je pensais que je voudrais partager. Si vous créez votre worker au niveau de la classe et que vous le réutilisez lors d'opérations successives sans fermer l'application, si vous ne supprimez pas les événements après leur exécution, ils seront incrémentés et exécutés plusieurs fois à chaque exécution successive.

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

Sans-dessus de mes feux de DoWork une fois la première fois, deux fois la deuxième fois, etc. Ceci est probablement une évidence pour la plupart, mais il m'a fallu un peu pour le comprendre, donc nous espérons que cette volonté aider quelqu'un d'autre.

+0

Pourriez-vous fournir un code plus détaillé de votre scénario. J'utilise BW et cela (pour autant que je sache) ne m'est jamais arrivé –

+0

Sans écrire un exemple complet il n'y a pas grand-chose à expliquer, mais je vais essayer. Si "worker" est défini en dehors des méthodes qui l'utilisent (c'est-à-dire globalement au niveau application), mais que vous inscrivez ce worker dans l'une de ces méthodes sans supprimer ledit abonnement à chaque itération, ses abonnements continueront à croître exponentiellement. – Paul

+0

Ma compréhension est que vous souscrivez les événements dans une méthode qui est appelée plusieurs fois. Si oui: oui, bien sûr; Sinon, je ne comprends toujours pas. –

1

worker.Dispose() n'est pas requis car Dispose() est automatiquement appelé. Mais avant de disposer de l'objet, vous devez supprimer tous les gestionnaires d'événements.

Cette article nous informe à ce sujet.

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

S'il était vrai que l'article mentionnait la suppression des gestionnaires d'événements, ce n'est plus le cas. Dans toutes les versions de l'article lié, aucune mention n'est faite des événements. – kbrimington

Questions connexes