什么是.dispose()的最佳应用

时间:2008-10-06 19:05:51

标签: vb.net

这是我在.NET中从未完全掌握的.dispose()方法的正确应用。

说我有类似

的东西
Public Class someClass()
  sub someMethod
    ' do some stuff tying up resources
  end sub
End Class

public class mainApp 
  dim _class as new SomeClass
  _class.someMethod()
End Class

在所有情况下,实施dispose方法都是一种好习惯,如果是这样,应该去哪里?

如果不是每个班级都应该有处理方法(我的直觉不应该说)应该是什么类?我一直认为任何可能占用资源的东西(即连接,datareader等)都应该有一个.dispose(),它会取消分配这些资源。

另外,如何强制调用.dispose()方法?

6 个答案:

答案 0 :(得分:6)

完全涵盖所有内容是一个相当长的答案,所以如果我链接到a blog post which should hopefully answer everything,没有人会介意。

答案 1 :(得分:5)

我强烈建议在MSDN上阅读Cleaning Up Unmanaged Resources,它有文章介绍何时使用Dispose以及如何正确实现IDisposable。您的直觉本质上是正确的,因为您很少需要实现IDisposable,除非您的类使用非托管资源或者是实现IDisposable的对象的容器。

至于强制调用Dispose,当你正确实现IDisposable接口时,你会附加一个终结器,它调用Dispose来捕获那些遗忘的落后者和异常类。

相关文章:

  

<强> Implementing a Dispose Method

     

描述用于释放非托管资源的Dispose方法的实现。

     

<强> Using Objects That Encapsulate Resources

     

描述确保调用Dispose方法的方法,例如C#using语句(在Visual Basic中使用)。

(编辑:添加了其他信息)

在您的示例中,您有 SomeClass.SomeMethod ,它可以完成一些工作,大概是使用资源。如果此资源不是类成员,则可以更好地将其包装在using-statement中,并忘记IDisposable的恶魔细节。

Public Class someClass()
  sub someMethod
    Using someResource As New ResourceType( arguments )
       ' no worries about IDisposable for someResource, as it is automatic
    End Using
  end sub
End Class

答案 2 :(得分:1)

关于IDisposable有很多错误的信息。它是一个PATTERN,有助于完成以前通过C ++中的析构函数完成的工作。问题是在.NET中,对象的破坏不是确定性的(当对象超出范围时它不会自动发生,而是在垃圾收集时发生,而垃圾收集是在一个单独的低优先级线程上)。 / p>

除非您拥有需要以某种方式发布的资源,否则不需要实现Dispose。例如,如果您的任何私有数据成员实现Dispose,您可能也应该实现Dispose并在Dispose中的那些私有成员上调用Dispose。同样,您应该在Dispose中释放任何PInvoke句柄。

此外,在收集垃圾时,不会自动为您调用Dispose方法。这是最大的错误信息。您必须从析构函数(C#)或Finalize(VB.NET)调用Dispose。这是实现Dispose的一个很好的模式:

public class Foo : IDisposable
{
   public Foo()
   {
      // Allocate some resource here
   }

   ~Foo()
   {
      Dispose( false );
   }

   public void Dispose()
   {
      Dispose( true );
   }

   private void Dispose( bool disposing )
   {
      // De-allocate resource here
      if ( disposing )
         GC.SuppressFinalize( this );
   }
}

你调用GC.SupressFinalize的原因是如果你的对象有一个终结器,你的对象实际上会升级到下一代GC,因为它必须在GC第一次运行时调用Finalize,而不能释放您的对象,直到完成结束,因此在GC第二次运行之前,内存实际上不会被释放。如果您手动调用Dispose,则可以跳过终结器,允许在GC的第一次传递期间释放您的对象。

要从Dispose中获得最大收益,请使用using keword:

using ( Foo f = new Foo() )
{
   // Do something with Foo
}

这与你写下来的完全相同:

Foo f;
try
{
   f = new Foo();
   // Do something with Foo
}
finally
{
   f.Dispose();
}

有些人喜欢在他们的类中设置一个名为_disposed的布尔值,然后在每个方法调用期间检查bool,如果在调用Dispose后尝试调用对象上的方法,则抛出异常。对于内部项目类,我通常认为这有点过分,但如果您要创建供第三方使用的库,则可能是一件好事。

答案 3 :(得分:0)

Dispose()方法用于尽早清理所有资源。尽管垃圾收集器会为您回收任何未使用的内存,但您可以自行处理网络/数据库连接和文件句柄等操作。通常情况下,您希望这些东西在不再需要时立即释放,因此您可以实现一次性模式并利用Using语句在后台的try / finally块中调用它。

答案 4 :(得分:0)

一般情况下,只要您的课程打算打开某些内容,就应该实施IDisposable。无论是文件的句柄,与数据库的连接,还是某些会占用大量内存的资源,或者会使应用程序处于不稳定状态的资源,实现IDisposable以指定代码都是一个好主意。关闭这些资源。

您实际上无法强制其他开发人员调用您的dispose方法,但自动实现IDisposable意味着我们可以使用Using语句;一旦你养成习惯,就很难打破:)

答案 5 :(得分:0)

如果类是:

,您应该在类中实现IDisposable
  • 拥有一些实现IDisposable的其他对象
  • 通过非托管接口(如P / Invoke)分配一些资源。