2010-03-30 2 views
45

Будет ли это правильным способом утилизации BackGroundWorker? Я не уверен, нужно ли удалять события перед вызовом .Dispose(). Также вызывает вызов .Dispose() внутри делегата RunWorkerCompleted ok?Правильный способ утилизации 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

Это работник фона на форме? –

+0

Да, хотя я создал программный продукт BGW программно, а не отбрасывал его в форме в дизайнере. Как показано, BGW создается, когда я хочу запустить поток. Идея заключалась в том, чтобы создавать разные BGW каждый раз, когда поток был вызван и избавлен от них, когда они завершены. – galford13x

ответ

67

BackgroundWorker происходит от компонента. Компонент реализует интерфейс IDisposable. Это в свою очередь заставляет BackgroundWorker наследовать метод Dispose().

Получение из компонента удобство для программистов Windows Forms, они могут отбросить BGW из панели инструментов на форму. Компоненты в целом, скорее всего, будут иметь что-то распоряжаться. Дизайнер Windows Forms позаботится об этом автоматически, загляните в файл Designer.cs для формы для поля «components». Его автоматически созданный метод Dispose() вызывает метод Dispose() для всех компонентов.

Однако BackgroundWorker фактически не имеет ни одного члена, который требует утилизации. Он не переопределяет Dispose(). Его базовая реализация, Component.Dispose(), только гарантирует, что компонент будет удален из коллекции «components». И поднимите Disposed событие. Но иначе ничего не распоряжается.

Короче говоря: если вы сбросили BGW на форму, тогда все будет заботиться автоматически, вам не нужно помогать. Если вы не отбросили его на форму, это не элемент в коллекции компонентов, и ничего не нужно делать.

Вам не нужно вызывать Dispose().

+6

Лично мне нравится следовать политике вызова 'Dispose', если она присутствует в случае, когда реализация класса действительно изменяется ... –

+3

Я не могу с этим спорить. Но предпочитают всегда думать: «Какой объект может быть обернут классом, который требует утилизации?» И посмотри. У меня проблемы с написанием кода, который не имеет смысла и не покупает понятие о том, что это будет иметь смысл в один прекрасный день. Он работает и наоборот: класс Thread действительно имеет одноразовые объекты, но не реализует IDisposable. Каждому свое. –

+1

Просто так понимаю. BGW не нужно удалять, поскольку ему нечего утилизировать? Я когда-то читал, что если события не удаляются, они могут продолжать болтаться, предотвращая освобожденные ресурсы, когда объект, который полагается на них, удаляется. Разве это не так? – galford13x

0

Да, это кажется правильным. Конечно, одноразовые объекты лучше обрабатываются с помощью блоков using, но у вас нет этой опции.

Обычно я создаю свои помощники для фона с продолжительностью жизни формы, повторно их использую и позволяю коду конструктора обращаться с утилитой на форме. Меньше думать.

+0

Так я всегда это делал в прошлом. Хотя я не понимал, что сброс BackGroundWorker в WinForm во время разработки добавит BGW в список объектов, которые будут удаляться при размещении Формы. Я, как правило, создавал BGW программно. – galford13x

0

Если он находится на «WinForms» форма позволяет контейнеру заботиться о нем (см сгенерированного Dispose кода в файле Form.Designer.xyz)

На практике я обнаружил, что вам, возможно, потребуется создать экземпляр контейнера и добавить к нему рабочего (или другого сопутствующего), если кто-нибудь знает более официальный способ сделать это кричать!

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

Late к игре, но я просто наткнулся на сценарий, связанные с вашим вопросом, что я думал, что я хотел бы поделиться. Если вы создаете своего работника на уровне класса и повторно используете его при последовательных операциях без закрытия приложения, если вы не удаляете события после завершения, они будут увеличиваться и выполняться несколько раз при каждом последующем выполнении.

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

Без выше моих DoWork пожаров один раз в первый раз, два раза во второй раз, и т.д. Это, вероятно, никакой опасности для большинства, но он взял меня немного, чтобы понять это, так надеюсь, это помогите кому-то еще.

+0

Не могли бы вы предоставить более подробный код вашего сценария. Я использую BW, и это (насколько мне известно) никогда не случалось со мной –

+0

Не записывая полный пример, объяснять нечего, но я попробую. если «рабочий» определен вне методов, которые его используют (т. е. глобально на уровне приложения), но вы подписываете этого работника в рамках одного из этих методов, не удаляя указанную подписку на каждой итерации, ее подписки будут продолжать расти экспоненциально. – Paul

+0

Я понимаю, что вы подписываете события в методе, который вызывается несколько раз. Если да: да, конечно; Если нет, я до сих пор не понимаю. –

1

worker.Dispose() не требуется, потому что Dispose() автоматически вызывается. Но перед удалением объекта вам нужно удалить все обработчики событий.

Этот article сообщает об этом.

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

Если некогда было правдой, что в статье упоминается удаление обработчиков событий, это уже не так. Во всех версиях связанной статьи не упоминаются события. – kbrimington

Смежные вопросы