2010-03-30 36 views
45

¿Esta sería una forma adecuada de deshacerse de un BackGroundWorker? No estoy seguro de si es necesario eliminar los eventos antes de llamar a .Dispose(). También está llamando .Dispose() dentro del delegado RunWorkerCompleted para hacer?Forma correcta de deshacerse de 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

¿es este un trabajador de fondo en un formulario? –

+0

Sí, así es, aunque creé el BGW programáticamente en lugar de colocarlo en el Formulario en el diseñador. Como se muestra, el BGW se crea cuando quiero ejecutar el hilo. La idea era crear un BGW diferente cada vez que se llamaba el hilo y deshacerse de ellos cuando se completaran. – galford13x

Respuesta

67

BackgroundWorker se deriva de Component. El componente implementa la interfaz IDisposable. Eso a su vez hace que BackgroundWorker herede el método Dispose().

Derivado de componentes es una conveniencia para los programadores de Windows Forms, pueden colocar un BGW de la caja de herramientas en un formulario. Es probable que los componentes en general tengan algo que desechar. El diseñador de Windows Forms se ocupa de esto automáticamente, busque en el archivo Designer.cs un Formulario para el campo "componentes". Su método Dispose() generado automáticamente llama al método Dispose() para todos los componentes.

Sin embargo, BackgroundWorker en realidad no tiene ningún miembro que requiera su eliminación. No anula Dispose(). Su implementación base, Component.Dispose(), solo se asegura de que el componente se elimine de la colección de "componentes". Y levanta el evento Disposed. Pero de otro modo no dispone de nada.

Resumen breve: si eliminó un BGW en un formulario, entonces todo se soluciona automáticamente, no tiene que ayudar. Si no lo colocó en un formulario, entonces no es un elemento en una colección de componentes y no es necesario hacer nada.

No tiene que llamar a Dispose().

+6

Personalmente me gusta seguir la política de llamar a 'Dispose' si está presente en caso de que la implementación de la clase realmente cambie ... –

+3

No puedo discutir eso. Pero prefiero siempre pensar: "¿qué tipo de objeto podría ser envuelto por una clase que requeriría deshacerse?" Y mira. Tengo problemas para escribir código que no tiene sentido y no creo en la idea de que tenga sentido algún día. También funciona al revés: la clase Thread realmente tiene objetos desechables pero no implementa IDisposable. A cada uno lo suyo. –

+1

Solo para que lo entiendo. No es necesario desechar un BGW ya que no tiene nada que desechar. En algún momento leí que, si los eventos no se eliminan, pueden continuar bloqueando la prevención de recursos liberados cuando se elimina un objeto que depende de ellos. ¿Nunca es este el caso? – galford13x

0

Sí, esto parece correcto. Por supuesto, los objetos desechables se manejan mejor con los bloques using, pero no tiene esa opción aquí.

Por lo general, creo mis ejecuciones de segundo plano con vidas útiles, las vuelvo a usar, y dejo que el código del diseñador maneje la eliminación en forma cerrada. Menos para pensar.

+0

Así es como siempre lo hice en el pasado. Aunque no me di cuenta de que al dejar un BackGroundWorker en un WinForm durante el tiempo de diseño agregué el BGW a la lista de objetos que se eliminarían cuando se elimine el formulario. En general, había creado el BGW programáticamente. – galford13x

0

Si está en un "Windows Forms" Formulario de dejar que el contenedor se encargue de ello (ver el código Dispose generado en el archivo Form.Designer.xyz)

En la práctica, he encontrado que es posible que deba crear una ejemplo del contenedor y agregue el trabajador (u otra compañía), si alguien conoce una forma más oficial de hacerlo, ¡grite!

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

tarde al juego, pero sólo encontré con un escenario relacionado a su pregunta que pensé que iba a compartir. Si crea su trabajador en el nivel de clase y lo reutiliza en operaciones sucesivas sin cerrar la aplicación, si no elimina los eventos después de la finalización, se incrementarán y ejecutarán varias veces en cada ejecución sucesiva.

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

Sin lo anterior mis fuegos DoWork una vez que la primera vez, dos veces el segundo tiempo, etc. Esto es probablemente una obviedad para la mayoría, pero me tomó un poco de entenderlo, así que espero que esta voluntad ayudar a alguien más a salir.

+0

¿Podría proporcionar un código más detallado de su escenario? uso BW y esto (hasta donde sé) nunca me pasó –

+0

Sin escribir un ejemplo completo, no hay mucho más que explicar, pero lo intentaré. si se define "trabajador" fuera de los métodos que lo utilizan (es decir, globalmente a nivel de aplicación), pero se suscribe ese trabajador en uno de esos métodos sin eliminar dicha suscripción en cada iteración, sus suscripciones continuarán creciendo exponencialmente. – Paul

+0

Según tengo entendido, estás suscribiendo los eventos en un método que se llama varias veces. Si es así: sí, por supuesto; Si no, todavía no lo capto. –

1

worker.Dispose() no se requiere, porque Dispose() se llama automáticamente. Pero antes de eliminar el objeto, debe eliminar todos los controladores de eventos.

Esto article nos informa sobre esto.

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

Si alguna vez fue cierto que el artículo menciona la eliminación de controladores de eventos, ya no es así. En todas las versiones del artículo vinculado, no se menciona ningún evento. – kbrimington

Cuestiones relacionadas