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

时间:2021-04-04 23:06:33

This is something that I have never fully grasped in .NET as to the correct application of the .dispose() method.

对于.dispose()方法的正确应用,我在.NET中从未完全掌握这一点。

Say I have something like

说我有类似的东西

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

In all cases is it good practice to implement a dispose method, and if so what should go in there?

在所有情况下,实施配置方法都是一种好的做法,如果是这样,应该在那里进行什么?

If it is not the case that every class should have dispose method (which my gut feeling says the shouldn't) what classes should? I have always thought anything which may tie up a resource (i.e. connection, datareader etc) should have a .dispose() which would unallocate these resources.

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

Also how would you enforce a calling into calling the .dispose() method?

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

6 个解决方案

#1


5  

I highly recommend reading Cleaning Up Unmanaged Resources on MSDN, it has articles touching on when to use Dispose and how to implement IDisposable correctly. Your gut instinct is mostly correct as you rarely have to implement IDisposable, unless your class uses unmanaged resources or is a container for an object that implements IDisposable.

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

As to enforcing the calling of Dispose, when you properly implement the IDisposable interface you attach a finalizer which calls Dispose to catch those stragglers and deviant classes that forgot.

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

Relevant articles:

Implementing a Dispose Method

实现Dispose方法

Describes the implementation of the Dispose method for releasing unmanaged resources.

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

Using Objects That Encapsulate Resources

使用封装资源的对象

Describes ways to ensure that the Dispose method is called, such as the C# using statement (Using in Visual Basic).

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

(edit: additional information added)

(编辑:添加了附加信息)

In your example you have SomeClass.SomeMethod which does some work, presumably with a resource. If this resource isn't a class member, you may be better served wrapping it in a using-statement, and forgetting about the devilish details of IDisposable.

在你的例子中,你有SomeClass.SomeMethod做了一些工作,可能是资源。如果此资源不是类成员,则可以更好地将其包装在using语句中,并忘记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


6  

It's a fairly long answer to cover everything fully, so hopefully nobody will mind if I link to a blog post which should hopefully answer everything.

完全覆盖所有内容是一个相当长的答案,所以如果我链接到一篇应该有希望回答所有内容的博客文章,我希望没有人会介意。

#3


1  

There is a lot of misinformation out there about IDisposable. It is a PATTERN that helps to accomplish what used to be traditionally accomplished via a destructor in C++. The problem is that in .NET, destruction of an object is not deterministic (it doesn't happen automatically when an object goes out of scope, but rather occurs at the time of Garbage Collection which is on a seperate low priority thread).

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

You do not need to implement Dispose unless you have a resource which needs to be released in some fashion. For instance, if any of your private data members implement Dispose, you should probably implement Dispose as well and call Dispose on those private members in your Dispose. Likewise, you should release any PInvoke handles in Dispose.

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

Also, the Dispose method is NOT called automatically for you upon garbage collection. This is the biggest piece of misinformation. You have to call Dispose from your Destructor (C#) or Finalize (VB.NET). Here is a good pattern for implementing Dispose:

此外,在收集垃圾时,不会自动为您调用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 );
   }
}

The reason that you call GC.SupressFinalize is that if your object has a finalizer, your object will actually get promoted to the next GC generation, because it has to call Finalize the first time the GC runs around, and can't release your object until finalization is finished, and therefore the memory is actually not released until the 2nd run through by the GC. If you call Dispose manually, then you can skip the finalizer, allowing your object to be released during the first pass of the GC.

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

To get the most benefit out of Dispose, use the using keword:

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

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

This is exactly the same as if you had written this:

这和你写的一样完全相同:

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

Some people like to set a boolean in their class called _disposed, and then check that bool during every method call, and throw an exception if you attempt to call a method on an object after Dispose is called. For internal project classes, I generally consider this overkill, but might be a good thing to do if you are creating a library for consumption by 3rd parties.

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

#4


0  

The Dispose() method is used for cleaning up any resources early. Although the garbage collector reclaims any unused memory for you, it's up to you to do deal with things like network/database connections and file handles. Normally, you'd want these things freed up as soon as they're no longer needed, so you implement the disposable pattern and take advantage of the Using statment for calling it within a try/finally block behind the scenes.

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

#5


0  

In general, you should you implement IDisposable whenever your class intends to OPEN something. Whether its a handle to a file, a connection to a database, or some resource which will take up a sizable chunk of memory or which will leave your application in an unstable state, it's always a good idea implement IDisposable to specify the code that will CLOSE those resources.

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

You really can't enforce other developers to call your dispose methods, but implementing IDisposable automatically means we can use the Using statement; which, once you get into the habit, is hard to break :)

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

#6


0  

You should implement IDisposable in a class if the class either:

如果类是以下类,您应该在类中实现IDisposable:

  • own some other objects which implement IDisposable
  • 拥有一些实现IDisposable的其他对象

  • allocates some ressources through an unmanaged interface like P/Invoke.
  • 通过像P / Invoke这样的非托管接口分配一些资源。

#1


5  

I highly recommend reading Cleaning Up Unmanaged Resources on MSDN, it has articles touching on when to use Dispose and how to implement IDisposable correctly. Your gut instinct is mostly correct as you rarely have to implement IDisposable, unless your class uses unmanaged resources or is a container for an object that implements IDisposable.

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

As to enforcing the calling of Dispose, when you properly implement the IDisposable interface you attach a finalizer which calls Dispose to catch those stragglers and deviant classes that forgot.

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

Relevant articles:

Implementing a Dispose Method

实现Dispose方法

Describes the implementation of the Dispose method for releasing unmanaged resources.

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

Using Objects That Encapsulate Resources

使用封装资源的对象

Describes ways to ensure that the Dispose method is called, such as the C# using statement (Using in Visual Basic).

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

(edit: additional information added)

(编辑:添加了附加信息)

In your example you have SomeClass.SomeMethod which does some work, presumably with a resource. If this resource isn't a class member, you may be better served wrapping it in a using-statement, and forgetting about the devilish details of IDisposable.

在你的例子中,你有SomeClass.SomeMethod做了一些工作,可能是资源。如果此资源不是类成员,则可以更好地将其包装在using语句中,并忘记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


6  

It's a fairly long answer to cover everything fully, so hopefully nobody will mind if I link to a blog post which should hopefully answer everything.

完全覆盖所有内容是一个相当长的答案,所以如果我链接到一篇应该有希望回答所有内容的博客文章,我希望没有人会介意。

#3


1  

There is a lot of misinformation out there about IDisposable. It is a PATTERN that helps to accomplish what used to be traditionally accomplished via a destructor in C++. The problem is that in .NET, destruction of an object is not deterministic (it doesn't happen automatically when an object goes out of scope, but rather occurs at the time of Garbage Collection which is on a seperate low priority thread).

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

You do not need to implement Dispose unless you have a resource which needs to be released in some fashion. For instance, if any of your private data members implement Dispose, you should probably implement Dispose as well and call Dispose on those private members in your Dispose. Likewise, you should release any PInvoke handles in Dispose.

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

Also, the Dispose method is NOT called automatically for you upon garbage collection. This is the biggest piece of misinformation. You have to call Dispose from your Destructor (C#) or Finalize (VB.NET). Here is a good pattern for implementing Dispose:

此外,在收集垃圾时,不会自动为您调用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 );
   }
}

The reason that you call GC.SupressFinalize is that if your object has a finalizer, your object will actually get promoted to the next GC generation, because it has to call Finalize the first time the GC runs around, and can't release your object until finalization is finished, and therefore the memory is actually not released until the 2nd run through by the GC. If you call Dispose manually, then you can skip the finalizer, allowing your object to be released during the first pass of the GC.

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

To get the most benefit out of Dispose, use the using keword:

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

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

This is exactly the same as if you had written this:

这和你写的一样完全相同:

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

Some people like to set a boolean in their class called _disposed, and then check that bool during every method call, and throw an exception if you attempt to call a method on an object after Dispose is called. For internal project classes, I generally consider this overkill, but might be a good thing to do if you are creating a library for consumption by 3rd parties.

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

#4


0  

The Dispose() method is used for cleaning up any resources early. Although the garbage collector reclaims any unused memory for you, it's up to you to do deal with things like network/database connections and file handles. Normally, you'd want these things freed up as soon as they're no longer needed, so you implement the disposable pattern and take advantage of the Using statment for calling it within a try/finally block behind the scenes.

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

#5


0  

In general, you should you implement IDisposable whenever your class intends to OPEN something. Whether its a handle to a file, a connection to a database, or some resource which will take up a sizable chunk of memory or which will leave your application in an unstable state, it's always a good idea implement IDisposable to specify the code that will CLOSE those resources.

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

You really can't enforce other developers to call your dispose methods, but implementing IDisposable automatically means we can use the Using statement; which, once you get into the habit, is hard to break :)

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

#6


0  

You should implement IDisposable in a class if the class either:

如果类是以下类,您应该在类中实现IDisposable:

  • own some other objects which implement IDisposable
  • 拥有一些实现IDisposable的其他对象

  • allocates some ressources through an unmanaged interface like P/Invoke.
  • 通过像P / Invoke这样的非托管接口分配一些资源。