2010-03-30 23 views
45

Questo sarebbe un modo corretto di disporre di un BackGroundWorker? Non sono sicuro che sia necessario rimuovere gli eventi prima di chiamare .Dispose(). Chiama anche .Dispose() all'interno del delegato RunWorkerCompleted, ok?Modo corretto per smaltire 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

è un lavoratore in background su un modulo? –

+0

Sì, lo è, anche se ho creato il BGW a livello di codice anziché rilasciandolo nel modulo nel designer. Come mostrato, il BGW viene creato quando voglio eseguire il thread. L'idea era di creare un BGW diverso ogni volta che veniva chiamato il thread e smaltirli quando sono stati completati. – galford13x

risposta

67

BackgroundWorker deriva da Component. Componente implementa l'interfaccia IDisposable. Ciò a sua volta fa in modo che BackgroundWorker erediti il ​​metodo Dispose().

Derivando da Component è una comodità per i programmatori di Windows Form, possono rilasciare una BGW dalla casella degli strumenti su un modulo. I componenti in genere hanno una certa probabilità di avere qualcosa da smaltire. Il progettista di Windows Form si occupa automaticamente di questo, cerca nel file Designer.cs un modulo per il campo "componenti". Il suo metodo Dispose() generato automaticamente chiama il metodo Dispose() per tutti i componenti.

Tuttavia, BackgroundWorker in realtà non ha alcun membro che richiede lo smaltimento. Non sovrascrive Dispose(). La sua implementazione di base, Component.Dispose(), fa in modo che il componente venga rimosso dalla raccolta "components". E solleva l'evento Disposed. Ma non disponga altrimenti nulla.

Per farla breve: se si rilascia una BGW su un modulo, tutto viene gestito automaticamente, non è necessario fornire assistenza. Se non lo hai lasciato su un modulo, allora non è un elemento in una raccolta di componenti e non è necessario fare nulla.

Non è necessario chiamare Dispose().

+6

Personalmente mi piace seguire la politica di chiamare 'Dispose' se presente nel caso in cui l'implementazione della classe cambi effettivamente ... –

+3

Non posso discuterne. Ma preferisco sempre pensare: "quale tipo di oggetto potrebbe essere avvolto da una classe che richiederebbe lo smaltimento?" E dai un'occhiata. Ho problemi a scrivere codice che non ha senso e non comprendo l'idea che un giorno avrà senso. Funziona anche il contrario: la classe Thread ha davvero oggetti usa e getta ma non implementa IDisposable. A ciascuno il suo. –

+1

Solo così capisco. Una BGW non ha bisogno di essere smaltita in quanto non ha nulla da smaltire? Una volta avevo letto che se gli eventi non vengono rimossi, possono continuare a bloccarsi, impedendo la liberazione delle risorse quando un oggetto che si basa su di essi viene eliminato. Non è mai così? – galford13x

0

Sì, questo sembra corretto. Naturalmente, gli oggetti usa e getta sono meglio gestiti con i blocchi using, ma qui non si dispone di questa opzione.

Generalmente creo i miei handler di sfondo con le durate dei moduli, li riutilizza e lascia che il codice del designer gestisca lo smaltimento in base alla forma. Meno da pensare.

+0

È così che l'ho sempre fatto in passato. Anche se non mi ero reso conto che l'interruzione di un BackGroundWorker su un WinForm durante la progettazione, aggiungeva il BGW all'elenco di oggetti che sarebbero stati eliminati quando il Modulo è stato eliminato. Generalmente avevo creato la BGW a livello di programmazione. – galford13x

0

Se è su una "WinForms" Modulo di lasciare che il contenitore di prendersi cura di essa (vedere il codice generato Dispose nel file Form.Designer.xyz)

In pratica ho trovato che potrebbe essere necessario creare un istanza del contenitore e aggiungere il lavoratore (o altro) ad esso, se qualcuno conosce un modo più ufficiale per farlo urlare !!

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

ritardo al gioco, ma ho appena imbattuto in uno scenario correlato alla tua domanda che ho pensato di condividere. Se si crea il lavoratore a livello di classe e lo si riutilizza nelle operazioni successive senza chiudere l'app, se non si rimuovono gli eventi dopo il completamento, questi verranno incrementati ed eseguiti più volte in ogni esecuzione successiva.

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

Senza la di sopra delle mie incendi DoWork una volta la prima volta, due volte la seconda volta, ecc Questo è probabilmente un gioco da ragazzi per la maggior parte, ma mi c'è voluto un po 'per capirlo, quindi spero che questo testamento aiuta qualcun altro a uscire.

+0

Potresti fornire un codice più dettagliato del tuo scenario. io uso BW e questo (per quanto ne so) non mi è mai successo –

+0

Senza scrivere un esempio completo non c'è molto altro da spiegare, ma ci proverò. se "lavoratore" è definito al di fuori dei metodi che lo utilizzano (cioè a livello globale a livello di applicazione), ma tu sottoscrivi quel lavoratore all'interno di uno di questi metodi senza rimuovere detta iscrizione su ogni iterazione, le sue sottoscrizioni continueranno a crescere esponenzialmente. – Paul

+0

La mia comprensione è che si stanno sottoscrivendo gli eventi in un metodo chiamato più volte. Se sì: sì, certo; Se no, ancora non lo prendo. –

1

worker.Dispose() non richiesto, poiché viene chiamato automaticamente Dispose(). Ma prima di smaltire l'oggetto è necessario rimuovere tutti i gestori di eventi.

Questo article ci informa su questo.

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

Se una volta era vero che l'articolo menzionava la rimozione dei gestori di eventi, non lo è più. In tutte le versioni dell'articolo collegato, non si fa menzione di eventi. – kbrimington

Problemi correlati