实现IDisposable对不需要它的类的影响?

时间:2010-08-02 19:30:01

标签: .net asp.net idisposable

我再次运行静态分析检查,我在

上得到了100多个唠叨
Label foo = new Label(); //Where this is an ASP.NET web forms label

我是否需要在这些网络表单标签上调用dispose?另外,页面生命周期的后期是否可以安全地调用Dispose?如果一个类实现了IDisposable,但实际上没有做任何事情,那么不调用dispose会有什么危害吗?

(是的,我已经读过关闭连接是一件好事,使用块也是一件好事。)

DataSet是另一个似乎因为莫名其妙的原因而实现IDisposable的类。

4 个答案:

答案 0 :(得分:6)

实际上,您无需在添加到父网页的网络表单控件上调用Dispose()。我也看到了这些警告,并试图弄清楚如何处理它们,然后在using语句中包装所有控件创建之前,我测试了是否实际调用了一个已添加到父级的控件上的dispose

TestDispose.ascx.cs:

public partial class TestDispose : System.Web.UI.UserControl {
  public void override Dispose() {
    // Set breakpoint here
    base.Dispose();
  }
}

TestPage.aspx.cs:

public partial class TestPage : System.Web.UI.Page {
  public void override OnInit() {
    // test will be disposed of when the page is destroyed
    TestDispose test = new TestDispose();
    test.ID = "TestDispose";
    this.Controls.Add(test);

    // test1 will not be disposed of because it was not added
    // to the page's control tree.
    TestDispose test1 = new TestDispose();
    test1.ID = "TestDispose1";
  }
}

如果在调试器中使用TestDispose.Dispose()上的断点运行此操作,您将发现父页面在页面被销毁时调用Dispose()。一旦我确定了这一点,我就开始添加排除项,并在页面控制树中的对象上调用“Dispose()”。

更新

困扰我的一件事是我无法在任何地方找到它。虽然ASP.Net Page Lifecycle是一个很好的资源,但它没有提到在子控件上调用Dispose()

然而,使用Reflector,我能够确定通过以下层次结构调用Dispose()

System.Web.UI.Page.AspCompatBeginProcessRequest
-> System.Web.UI.Page.ProcessRequest
   -> System.Web.UI.Page.ProcessRequestCleanup
      -> System.Web.UI.Control.UnloadRecursive

System.Web.UI.Control.UnloadRecursive将遍历每个Controls属性,并最终为每个Control对象调用Dispose()。任何继承自System.Web.UI.UserControl的对象都会实现IDisposable

所以,遗憾的是,如果没有实际的文档,我们目前依赖的是实现细节,而不是合同。虽然我不会因此而改变我的排除/理由,但我只是想为这个答案的其他读者揭示这一点。

答案 1 :(得分:3)

  

如果一个类实现了IDisposable,但实际上没有做任何事情,那么不调用dispose会有什么害处吗?

如果班级没有做任何事情,那么不调用dispose是没有害处的。但是,您正在假设a)实现不会改变,b)没有任何子类化

  

DataSet是另一个似乎因莫名其妙的原因实现IDisposable的类

关于DataSet本身的主题,有a question here on Stack Overflow得出结论,处理它会加速内存清理,因为它是MarshalByValueComponent。

我认为一个好的经验法则是:如果你知道实现没有做任何事情并且很容易处理,那么处理它,但不要忘记你的方式(比如设置Page.Unload事件)处理者)去做。但是,如果您知道它释放非托管资源,总是处理它,除非文档另有说明(ala SharePoint)。

答案 2 :(得分:1)

你必须仔细看看课程。如果它只是一个无害的Dispose(),那么你可以忽略它。有几个类因为它们的基类而拥有它。

反对这种推理的主要论点是:它可能会在未来的版本中发生变化。但不太可能是Label。

但要小心,如果类(或其基类)实现完整的Disposable模式,它也可能有一个析构函数(Finalizer)。然后非常需要Dispose()来取消终结器。不这样做会严重损失性能。

答案 3 :(得分:0)

是的,如果Dispose()方法没有做任何事情,那么不调用Dispose将是无害的。如果您的静态分析工具实际上正在使用这些工具,那么如果您计划使用Winforms,则应该将其关闭。 IMO,这不是一个好的分析,因为有很多场景已知Dispose()被链接,只有根调用是必要的(即流/读者)。