Потоки считаются корневыми объектами; Я не знаю точно, как работает BackgroundWorker, но кажется вероятным, что метод основного потока собирается получить доступ к состоянию на рабочем экземпляре; таким образом, сам рабочий поток будет поддерживать экземпляр BackgroundWorker до тех пор, пока (по крайней мере) поток не завершится.
Конечно; коллекция также требует, чтобы все другие (живые) объекты разыменовали рабочий объект; также обратите внимание, что набор переменных стека может быть разным в отладке / выпуске и с / без присоединенного отладчика.
[править]
Как также было отмечено; обработчики событий на рабочем (в вашем коде) будут поддерживать объекты «просмотр» и «обновление» (через делегат), но не наоборот. Пока у работника короче срок службы, чем у «просмотра» и «обновления», вам не нужно быть параноиком по поводу отмены подписки на события. Я отредактировал код, добавив в него объект SomeTarget, на который ссылается только работник: вы должны увидеть этот эффект (то есть цель умирает вместе с работником).
Повторный сбор работника, когда нить умирает: вот доказательство; вы должны увидеть «рабочий завершен» после выхода рабочих отчетов:
using System;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;
class Demo : Form
{
class ChattyWorker : BackgroundWorker
{
~ChattyWorker()
{
Console.WriteLine("Worker finalized");
}
}
class SomeTarget
{
~SomeTarget()
{
Console.WriteLine("Target finalized");
}
public SomeTarget()
{
Console.WriteLine("Target created");
}
public void Foo(object sender, EventArgs args)
{
Console.WriteLine("Foo");
}
}
static void Collect(object sender, EventArgs args)
{
Console.WriteLine("Collecting...");
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
timer.Interval = 100;
timer.Tick += Collect;
timer.Start();
ChattyWorker worker = new ChattyWorker();
worker.RunWorkerCompleted += new SomeTarget().Foo;
worker.DoWork += delegate
{
Console.WriteLine("Worker starting");
for (int i = 0; i < 10; i++)
{
Thread.Sleep(250);
Console.WriteLine(i);
}
Console.WriteLine("Worker exiting");
};
worker.RunWorkerAsync();
}
[STAThread]
static void Main()
{ // using a form to force a sync context
Application.Run(new Demo());
}
}