Proper way to Dispose of a BackGroundWorker

C#.NetMultithreadingBackgroundworker

C# Problem Overview


Would this be a proper way to dispose of a BackGroundWorker? I'm not sure if it is necesary to remove the events before calling .Dispose(). Also is calling .Dispose() inside the RunWorkerCompleted delegate ok to do?

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

C# Solutions


Solution 1 - C#

BackgroundWorker derives from Component. Component implements the IDisposable interface. That in turn makes BackgroundWorker inherit the Dispose() method.

Deriving from Component is a convenience for Windows Forms programmers, they can drop a BGW from the toolbox onto a form. Components in general are somewhat likely to have something to dispose. The Windows Forms designer takes care of this automatically, look in the Designer.cs file for a Form for the "components" field. Its auto-generated Dispose() method calls the Dispose() method for all components.

However, BackgroundWorker doesn't actually have any member that requires disposing. It doesn't override Dispose(). Its base implementation, Component.Dispose(), only makes sure that the component is removed from the "components" collection. And raise the Disposed event. But doesn't otherwise dispose anything.

Long story short: if you dropped a BGW on a form then everything is taken care of automatically, you don't have to help. If you didn't drop it on a form then it isn't an element in a components collection and nothing needs to be done.

You don't have to call Dispose().

Solution 2 - C#

Late to the game, but I just ran across a scenario related to your question that I thought I would share. If you create your worker at the class level and reuse it on successive operations without closing the app, if you don't remove the events after completion they will increment and run multiple times on each successive execution.

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

Without the above my DoWork fires once the first time, twice the second time, etc. This is probably a no-brainer for most, but it took me a bit to figure it out, so hopefully this will help someone else out.

Solution 3 - C#

worker.Dispose() is not required, because Dispose() is automatically called. But before disposing the object you need to remove all events handlers.

This article informs us about this.

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

Solution 4 - C#

Yes, this appears proper. Of course, disposable objects are better handled with using blocks, but you don't have that option here.

I usually create my background handers with form lifetimes, reuse them, and let the designer code handle disposal on form close. Less to think about.

Solution 5 - C#

If it's on a "WinForms" Form let the container take care of it (see the generated Dispose code in the Form.Designer.xyz file)

In practice I have found that you may need to create an instance of the container and add the worker (or other companent) to it, if anyone knows a more official way to do this yell out!!

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

}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questiongalford13xView Question on Stackoverflow
Solution 1 - C#Hans PassantView Answer on Stackoverflow
Solution 2 - C#PaulView Answer on Stackoverflow
Solution 3 - C#AlexNView Answer on Stackoverflow
Solution 4 - C#Michael PetrottaView Answer on Stackoverflow
Solution 5 - C#Paul KohlerView Answer on Stackoverflow