【问题标题】:Who owns controls?谁拥有控制权?
【发布时间】:2013-03-02 06:12:21
【问题描述】:

假设我有一些这样的组件:

class SomeForm : Form
{
    private Control example;

    public void Stuff()
    {
        this.example = new ComboBox();
        // ...
        this.Controls.Add(example);
    }

    public void OtherStuff()
    {
        this.Controls.Remove(example);
    }
}

谁负责在示例控件上调用Dispose?从this.Controls 中删除它会导致它被丢弃吗?或者这是否会泄漏支持控件的窗口句柄?

(作为参考,我之所以问这个问题是因为我看不到 Windows 窗体设计器在何处生成代码以在窗体的子级上调用 Dispose)

【问题讨论】:

    标签: c# .net winforms idisposable


    【解决方案1】:

    Form.Dispose() 将处置Controls 集合中的控件。因此,从 Controls 中删除控件将需要您自己处置该控件。

    【讨论】:

      【解决方案2】:

      释放包含此控件的表单时,将释放存储在 Controls 属性中的所有控件。您不需要从集合中删除您的自定义控件。只需确保释放包含表单即可。

      如果您从集合中删除该控件,则该控件最终将超出范围并且无法进行垃圾回收。当 GC 运行时,它将调用终结器/析构函数,在 Form 类的情况下,它将简单地调用 Dispose 方法。话虽这么说,依赖它是不好的做法。您应该始终确保在完成使用 IDisposable 接口的类上确定性地(手动)调用 Dispose 方法。

      【讨论】:

      • 所以你断言控件会被泄露?
      • 绝对不是。正如我在回答中所说,当包含表单被释放时,Controls 属性内的所有控件都将被释放。所以你需要做的就是确保包含的表单实例被释放。
      • 控件不在Controls 集合中,因为他在处置父项之前将其从该集合中删除。您似乎错过了问题的全部要点。
      • @Darin:所以,如果从表单中删除一个控件,必须确保在其上调用Dispose
      • @BillyONEal,但这不是内存泄漏!内存泄漏意味着您的程序正在使用越来越多的内存,直到最终出现 OutOfMemoryException ,而这里根本不是这种情况。如果机器上有足够的内存,终结器可能不会运行。但是一旦您的机器开始在低内存上运行,GC 将运行调用终结器,因此您的示例代码不会泄漏任何内存。但正如我已经解释过的,最好在使用完 IDisposable 接口后立即确定性地处理实现 IDisposable 接口的类。
      【解决方案3】:

      总是去怀疑的源头:

      Form.Dispose 有点像这样:

      protected override void Dispose(bool disposing)
      {
          if (disposing)
          {
             ... lots and lots of weird optimized checks ...
             base.Dispose(disposing);
      

      好的...FormContainerControl,所以:

      ContainerControl.Dispose:

      protected override void Dispose(bool disposing)
      {
          if (disposing)
          {
              this.activeControl = null;
          }
          base.Dispose(disposing);
          this.focusedControl = null;
          this.unvalidatedControl = null;
      }
      

      Grrr*...好吧,ContainerControlControl

      Control.Dispose:

      protected override void Dispose(bool disposing)
      {
          ... a whole lot of resource reclaiming/funky code ...
           ControlCollection controls = (ControlCollection) 
                  this.Properties.GetObject(PropControlsCollection);
           if (controls != null)
           {
               for (int i = 0; i < controls.Count; i++)
               {
                    Control control = controls[i];
                    control.parent = null;
                    control.Dispose();
               }
               this.Properties.SetObject(PropControlsCollection, null);
            }
            base.Dispose(disposing);
      

      所以是的;在 Form 上调用 Dispose 将释放其中包含的控件。

      【讨论】:

      • 这不是问题要问的;它询问在处置表单时是否仅处置 Controls 集合中的控件,这意味着如果他移除了控件(他这样做),他现在是否负责处置它,或者是否有其他机制(例如处置从集合中删除它时的控件),以防止他需要处理它。
      • @Servy:我对两者都感兴趣
      • @Servy 我怎么会错过呢?更简单的答案:不,从表单中弹出一个控件(从 Controls 删除)基本上将它与 Form 分离。
      • @BillyONEal Reflector 需要花钱,dotPeek 仍然是免费的(我相信),Rotor 包含很多 CLR 代码库,Mono(虽然在这种情况下没有用)在很多地方都紧跟 BCL。
      • 值得注意的是,您可以创建自己的扩展控制的类,在您覆盖的 Dispose 方法中进行一些日志记录,然后进行大量实验以查看该方法是否被调用或不。它可能不是“证明”,但它是一个很好的起点。
      猜你喜欢
      • 1970-01-01
      • 2014-02-24
      • 1970-01-01
      • 1970-01-01
      • 2010-10-26
      • 2015-01-22
      • 2011-08-10
      • 2011-04-11
      • 1970-01-01
      相关资源
      最近更新 更多