10

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?

braX
  • 11,506
  • 5
  • 20
  • 33
serhio
  • 28,010
  • 62
  • 221
  • 374
  • If there's a call to Dispose in the finalizer, they will get disposed. If there's not, then there's probably (if the programmer followed accepted practices) nothing unmanaged to dispose and it's safe to just garbage collect them. – Aviad P. Dec 28 '09 at 14:32
  • @Aviad: The problem that the Dispose method will never be called by the GC, so you need to do it by yourself, before calling Clear on collection. – serhio Dec 28 '09 at 14:42
  • What I mean is, if the control's programmer did not put a Dispose call in its finalizer (which is called when the object is garbage collected) - then there's probably nothing to dispose. – Aviad P. Dec 28 '09 at 15:07
  • See also Hans's detailed description of the problems here: http://stackoverflow.com/a/2014427/366904 – Cody Gray - on strike Dec 23 '16 at 14:33

3 Answers3

18

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);
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • 1
    IIRC, when you `Dispose` a `Control`, it automatically removes the control from the corresponding `ControlCollection`, so you actually don't need the `RemoveAt` (and might end up with an `IndexOutOfRangeException`). – Aaronaught Dec 28 '09 at 16:20
  • yeah... at least for .NET 2 this will not work. But the question is a little bit other. Is there a "risk" do calling "Clear" without Dispose? – serhio Dec 28 '09 at 16:23
  • 2
    Of course, you'll leak the controls. Wasn't that obvious from the other threads? – Hans Passant Dec 28 '09 at 16:32
  • @nobugs: yes, now, in other words, you say that, normally, calling `Clear` without `Dispose` has no sense; Microsoft will not change the code, so all we have to do is remember that, use these methods together for .NET < 3.5 and maybe also implement extension methods in .NET >= 3.5 – serhio Dec 28 '09 at 16:39
  • 2
    Erm, I didn't say that. In fact, I don't think Clear() makes a lot of sense in general. WF was optimized to use UserControls and the designer. Container controls already know how to properly dispose their child controls. – Hans Passant Dec 28 '09 at 17:08
  • @nobugs: I think `Clear` it's a classic member of any collection(not only the component one), this should be its sense. Container controls "already know how to properly dispose"? What do you mean? As we can see this is not the "Clear" case. Probably they at least can add an "obsolete" attribute on the controls containers "Clear" method. – serhio Dec 28 '09 at 17:42
  • 2
    Disposing a control automatically disposes any child control in its Controls collection. No help is needed. – Hans Passant Dec 28 '09 at 18:11
  • @nobugs: Yes, you are right. BUT, *after* using CLEAR the parent will have *any* control in its controls collection, so all the controls that was `Clear` ed will remain un `Dispose` d, when the parent control is disposed. – serhio Dec 29 '09 at 10:15
  • @serhio: Are you sure that Controls.Clear() isn't overridden in ? I think it handles the dispose as Hans is pointing out. – styfle Mar 15 '12 at 21:47
  • Yes, `Control.Dispose()` will automatically remove the control from the parent `ControlCollection`, see https://source.dot.net/#System.Windows.Forms/System/Windows/Forms/Control.cs,5107 – dontbyteme Aug 24 '23 at 09:38
1

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());
Dave Cousineau
  • 12,154
  • 8
  • 64
  • 80
0

@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();
    }
  }
}
Alessandro Muzzi
  • 808
  • 1
  • 12
  • 26
  • `Control.Dispose()` will automatically remove the control from the parent `ControlCollection`, see [dot.net-source](https://source.dot.net/#System.Windows.Forms/System/Windows/Forms/Control.cs,5107). An additional `RemoveAt` would probably lead to an `IndexOutOfRangeException`. – dontbyteme Aug 24 '23 at 09:43