Let’s assume that inside a Windows Form, I start a long-running task like this:
ThreadPool.QueueUserWorkItem(new WaitCallback(UpdateDailyTasksChart));
Then, this function runs for a while, but I close the window before it finishes.
private void UpdateDailyTasksChart (object param)
{
//Call Data Access Layer, go get MySQL Data. But I close the Form.
UICallback(chartData); //The Form is closed when this is executed.
}
And now here’s what UICallback does:
private delegate void UICallbackDel(object chartData);
private void UICallback (object chartData)
{
if (InvokeRequired)
{
this.Invoke(new UICallbackDel(UICallback), chartData);
}
else
{
aButtonOnMyForm.Visible = false; //But the Form has been closed!
}
}
Curiously, this code doesn’t crash.
I placed breakpoints in the Form_Closed event and it does execute. I haven’t checked if the Form still exists by, for example, declaring it with a class variable. But my guess is that it does.
So the question is: the GC will only collect the Form when my thread finishes? Or what does it happen?
There are two points here:
ObjectDisposedExceptionwhen the work item delegate executes.this,InvokeRequired(which in turn referencesthis) andaButtonOnMyForm. Therefore, your form is ineligible for garbage collection as long as theThreadPoolthread has not completed execution. That’s why the code doesn’t crash. (Note:thisis always implicitly accessible regardless.)Another thing to derive from this is that it is generally wise to unregister external event handlers from a form before that form closes, lest you create memory leaks. The big gotcha there is if you register a lambda expression or anonymous delegate, you need to save off a reference to it in order to unregister later. Simply copying and pasting the same code would not work.