There are multiple threads(a, b, c etc.) about the fact that Clear() ing items in the .NET component containers does not Dispose them(by calling Dispose(true).
Most frequently, IMHO, the Clear-ed components are not used anymore in the application, so it needs explicitly be Disposed after Clearing them from the parent containers.
Maybe is a good idea that collection's Clear
method had a bool parameter dispose
that when in true also disposes the collection elements before its removing from the list?
Asking for modifications like this is pointless, the Windows Forms team has been disbanded quite a while ago. It is in maintenance mode, only security issues and OS incompatibilities are considered.
It is otherwise simple enough to create your own method to do this:
public static class ExtensionMethods {
public static void Clear(this Control.ControlCollection controls, bool dispose) {
for (int ix = controls.Count - 1; ix >= 0; --ix) {
if (dispose) controls[ix].Dispose();
else controls.RemoveAt(ix);
}
}
}
Now you can write:
panel1.Controls.Clear(true);
Answering the "what is the risk" question, the risk (or a risk) is running out of window handles, although it can take a while.
I have a "window designer" that generates a window from a script. Each time I change the script, the window is rebuilt (the controls cleared and readded). With a particularly complex window, and using Controls.Clear()
each time, after many dozens of refreshes, I will eventually get a "no more window handles" exception and not be able to create any more controls.
Easy enough to replace the Controls.Clear()
call with something like:
Controls.Cast<Control>().ForEach(c => c.Dispose());
@Hans Passant answer is good but in case of asynchronous programming you should consider to remove the object before dispose it to avoid some thread to iterate over a disposed object.
More or less something like this:
public static class ExtensionMethods {
public static void Clear(this Control.ControlCollection controls, bool dispose) {
for (int ix = controls.Count - 1; ix >= 0; --ix) {
var tmpObj = controls[ix];
controls.RemoveAt(ix);
if (dispose) tmpObj.Dispose();
}
}
}