IDisposable接口如何工作?

时间:2022-09-02 12:14:40

I understand that it is used to deallocate unmanaged resources, however, I am confused as to when Dispose is actually called. I know it is called at the end of a using block, but does it also get invoked when the object is garbage collected?

我知道它用于释放非托管资源,但是,我很困惑何时实际调用Dispose。我知道它在using块的末尾被调用,但是当对象被垃圾收集时它是否也会被调用?

5 个解决方案

#1


11  

If you implement IDisposable correctly, you should also include a finalizer that will call Dispose() on your object.

如果你正确实现了IDisposable,你还应该包含一个终结器,它将在你的对象上调用Dispose()。

If you do that, it will get called by the GC. However, it's still a VERY good idea to try to always dispose of these objects yourself.

如果这样做,它将被GC调用。但是,尝试始终自行处理这些对象仍然是一个非常好的主意。

The biggest problem with relying on the finalizer to call Dispose is that it will happen in another thread which you don't control. This can have nasty consequences in certain situations, including causing an exception that's happening in the GC thread, which is not good, as well as having a disposed field you check. This is also part of why including GC.SuppressFinalize(this) in your Dispose() method is important - once an object's disposed, you don't want to re-dispose it.

依赖终结器调用Dispose的最大问题是它将发生在你无法控制的另一个线程中。这可能会在某些情况下产生令人讨厌的后果,包括导致GC线程中发生的异常,这是不好的,以及您检查的处置字段。这也是为什么在Dispose()方法中包含GC.SuppressFinalize(this)很重要的原因 - 一旦对象被处理掉,你就不想重新处理它了。

#2


2  

Dispose is called in a few places:

在几个地方调用Dispose:

  1. At the end of a using block.
  2. 在使用块结束时。
  3. When explicitly called (in a try{} finally{} for instance.)
  4. 显式调用时(例如,在try {} finally {}中。)

It is recommended that you call it yourself when you are done with a resource, to better manage resources.

建议您在完成资源后自行调用,以便更好地管理资源。

EDIT: I was mistaken. Dispose is NOT called during garbage collection. See this article.

编辑:我错了。垃圾收集期间不调用Dispose。看到这篇文章。

#3


2  

No it does not get called when the object is garbage collected. If you want that behavior you can use the destructor (finalizer) and the call Dispose() from there.

当对象被垃圾收集时,不会调用它。如果你想要这种行为,你可以使用析构函数(终结器)和从那里调用Dispose()。

As you say it is automatically called and the end of a using block.

如你所说,它是自动调用和结束使用块。

#4


2  

Dispose() is called at the end of the Using block so that you can count on the Dispose actions (e.g. closing a db connection) to take place as the object goes out of scope. Simple as that.

在Using块的末尾调用Dispose(),这样当对象超出范围时,您可以指望Dispose操作(例如关闭数据库连接)。就那么简单。

Update: there is nothing specific to unmanaged resources in a call to Dispose (although that is a common use).

更新:在调用Dispose时没有特定于非托管资源的特定内容(尽管这是一种常见用法)。

Update 2: there is a bit of a debate on the thread that Reed Copsey started that is useful for understanding IDisposable. I highly recommend this article for people wanting to know more.

更新2:关于Reed Copsey开始的线程有一点争论,这对理解IDisposable非常有用。对于想要了解更多信息的人,我强烈推荐这篇文章。

In a nutshell, an IDisposable class allows you to explicitly handle the deallocation of resources (typically unmanaged resources or database connections) via the Dispose() method. IDisposable class instances should be created within a "Using" block so as to ensure that the Dispose method is actually called. If you fail to do this (or to call it explicitly in a "finally" block, etc.) then your Dispose method will not be called and you'll orphan the objects you'd like to clean up. In all cases, I place Disposable classes in Using blocks and you should too.

简而言之,IDisposable类允许您通过Dispose()方法显式处理资源的释放(通常是非托管资源或数据库连接)。应在“使用”块中创建IDisposable类实例,以确保实际调用Dispose方法。如果你没有这样做(或者在“finally”块中明确地调用它等),那么你的Dispose方法将不会被调用,你将孤立你要清理的对象。在所有情况下,我将Disposable类放在Using blocks中,你也应该这样做。

As an alternative you can handle the clean up of resources in a Finalizer (a class Destructor). This will be called automatically when the class is GC'd. The disadvantages of this approach are that you will not explicitly control when objects are cleaned up and there are some threading issues to contend with. Thus, for example, problems in Destructors are very difficult to debug due to the fact that they are called asynchronously and in a different thread. The only advantage is that you don't have to remember to call your Destructor like you do Dispose. Of course, if you always use Using blocks, this is a non-issue.

作为替代方案,您可以在Finalizer(类Destructor)中处理资源的清理。当类为GC时,将自动调用此方法。这种方法的缺点是您不会明确控制何时清理对象并且存在一些线程问题需要解决。因此,例如,析构函数中的问题非常难以调试,因为它们是异步调用并且在不同的线程中调用。唯一的好处是你不必记得像Dispose一样调用你的析构函数。当然,如果您始终使用“使用块”,则这不是问题。

NOTE: I ktrauberman, Reed and Pontus have made some good points about how you can get around the points I make below. This is what I do, but I cannot argue that this is the only way to do things. Indeed, Microsoft even recommends calling Dispose() from your Finalizer in some instances. However, I'll leave the discussion here just as an illustration of why it is important to follow Reed's advice re: being careful when mixing Destructors and Dispose().

注意:我ktrauberman,Reed和Pontus已经提出了一些关于如何绕过我在下面提出的观点的好点。这就是我所做的,但我不能说这是做事的唯一方法。实际上,Microsoft甚至建议在某些情况下从Finalizer中调用Dispose()。但是,我将在这里留下讨论,只是为了说明为什么遵循Reed的建议很重要:在混合Destructors和Dispose()时要小心。

Where I disagree with the Reed's answer is in the assertion that you should implement an IDisposable class by calling Dispose() within your Finalizer. This just conflates the two different constructs and may well lead to problems. For example, if you do create your IDisposable class instance in a Using block and you call Dispose() in the Destructor, it will be called twice - with potentially nasty and difficult to debug crashes (again - you don't control the timing of GC). (Side note: this is actually true of Destructors in general - they can, in certain circumstances be called more than once!)

我不同意Reed的答案是断言你应该通过在Finalizer中调用Dispose()来实现一个IDisposable类。这只会混淆两种不同的结构,很可能会导致问题。例如,如果您在Using块中创建了IDisposable类实例,并在Destructor中调用Dispose(),它将被调用两次 - 可能是令人讨厌且难以调试的崩溃(再次 - 您无法控制时间GC)。 (旁注:一般情况下,这对于Destructors来说确实如此 - 在某些情况下它们可以不止一次被调用!)

#5


0  

See this previous question: Proper use of the IDisposable interface

请参阅上一个问题:正确使用IDisposable接口

#1


11  

If you implement IDisposable correctly, you should also include a finalizer that will call Dispose() on your object.

如果你正确实现了IDisposable,你还应该包含一个终结器,它将在你的对象上调用Dispose()。

If you do that, it will get called by the GC. However, it's still a VERY good idea to try to always dispose of these objects yourself.

如果这样做,它将被GC调用。但是,尝试始终自行处理这些对象仍然是一个非常好的主意。

The biggest problem with relying on the finalizer to call Dispose is that it will happen in another thread which you don't control. This can have nasty consequences in certain situations, including causing an exception that's happening in the GC thread, which is not good, as well as having a disposed field you check. This is also part of why including GC.SuppressFinalize(this) in your Dispose() method is important - once an object's disposed, you don't want to re-dispose it.

依赖终结器调用Dispose的最大问题是它将发生在你无法控制的另一个线程中。这可能会在某些情况下产生令人讨厌的后果,包括导致GC线程中发生的异常,这是不好的,以及您检查的处置字段。这也是为什么在Dispose()方法中包含GC.SuppressFinalize(this)很重要的原因 - 一旦对象被处理掉,你就不想重新处理它了。

#2


2  

Dispose is called in a few places:

在几个地方调用Dispose:

  1. At the end of a using block.
  2. 在使用块结束时。
  3. When explicitly called (in a try{} finally{} for instance.)
  4. 显式调用时(例如,在try {} finally {}中。)

It is recommended that you call it yourself when you are done with a resource, to better manage resources.

建议您在完成资源后自行调用,以便更好地管理资源。

EDIT: I was mistaken. Dispose is NOT called during garbage collection. See this article.

编辑:我错了。垃圾收集期间不调用Dispose。看到这篇文章。

#3


2  

No it does not get called when the object is garbage collected. If you want that behavior you can use the destructor (finalizer) and the call Dispose() from there.

当对象被垃圾收集时,不会调用它。如果你想要这种行为,你可以使用析构函数(终结器)和从那里调用Dispose()。

As you say it is automatically called and the end of a using block.

如你所说,它是自动调用和结束使用块。

#4


2  

Dispose() is called at the end of the Using block so that you can count on the Dispose actions (e.g. closing a db connection) to take place as the object goes out of scope. Simple as that.

在Using块的末尾调用Dispose(),这样当对象超出范围时,您可以指望Dispose操作(例如关闭数据库连接)。就那么简单。

Update: there is nothing specific to unmanaged resources in a call to Dispose (although that is a common use).

更新:在调用Dispose时没有特定于非托管资源的特定内容(尽管这是一种常见用法)。

Update 2: there is a bit of a debate on the thread that Reed Copsey started that is useful for understanding IDisposable. I highly recommend this article for people wanting to know more.

更新2:关于Reed Copsey开始的线程有一点争论,这对理解IDisposable非常有用。对于想要了解更多信息的人,我强烈推荐这篇文章。

In a nutshell, an IDisposable class allows you to explicitly handle the deallocation of resources (typically unmanaged resources or database connections) via the Dispose() method. IDisposable class instances should be created within a "Using" block so as to ensure that the Dispose method is actually called. If you fail to do this (or to call it explicitly in a "finally" block, etc.) then your Dispose method will not be called and you'll orphan the objects you'd like to clean up. In all cases, I place Disposable classes in Using blocks and you should too.

简而言之,IDisposable类允许您通过Dispose()方法显式处理资源的释放(通常是非托管资源或数据库连接)。应在“使用”块中创建IDisposable类实例,以确保实际调用Dispose方法。如果你没有这样做(或者在“finally”块中明确地调用它等),那么你的Dispose方法将不会被调用,你将孤立你要清理的对象。在所有情况下,我将Disposable类放在Using blocks中,你也应该这样做。

As an alternative you can handle the clean up of resources in a Finalizer (a class Destructor). This will be called automatically when the class is GC'd. The disadvantages of this approach are that you will not explicitly control when objects are cleaned up and there are some threading issues to contend with. Thus, for example, problems in Destructors are very difficult to debug due to the fact that they are called asynchronously and in a different thread. The only advantage is that you don't have to remember to call your Destructor like you do Dispose. Of course, if you always use Using blocks, this is a non-issue.

作为替代方案,您可以在Finalizer(类Destructor)中处理资源的清理。当类为GC时,将自动调用此方法。这种方法的缺点是您不会明确控制何时清理对象并且存在一些线程问题需要解决。因此,例如,析构函数中的问题非常难以调试,因为它们是异步调用并且在不同的线程中调用。唯一的好处是你不必记得像Dispose一样调用你的析构函数。当然,如果您始终使用“使用块”,则这不是问题。

NOTE: I ktrauberman, Reed and Pontus have made some good points about how you can get around the points I make below. This is what I do, but I cannot argue that this is the only way to do things. Indeed, Microsoft even recommends calling Dispose() from your Finalizer in some instances. However, I'll leave the discussion here just as an illustration of why it is important to follow Reed's advice re: being careful when mixing Destructors and Dispose().

注意:我ktrauberman,Reed和Pontus已经提出了一些关于如何绕过我在下面提出的观点的好点。这就是我所做的,但我不能说这是做事的唯一方法。实际上,Microsoft甚至建议在某些情况下从Finalizer中调用Dispose()。但是,我将在这里留下讨论,只是为了说明为什么遵循Reed的建议很重要:在混合Destructors和Dispose()时要小心。

Where I disagree with the Reed's answer is in the assertion that you should implement an IDisposable class by calling Dispose() within your Finalizer. This just conflates the two different constructs and may well lead to problems. For example, if you do create your IDisposable class instance in a Using block and you call Dispose() in the Destructor, it will be called twice - with potentially nasty and difficult to debug crashes (again - you don't control the timing of GC). (Side note: this is actually true of Destructors in general - they can, in certain circumstances be called more than once!)

我不同意Reed的答案是断言你应该通过在Finalizer中调用Dispose()来实现一个IDisposable类。这只会混淆两种不同的结构,很可能会导致问题。例如,如果您在Using块中创建了IDisposable类实例,并在Destructor中调用Dispose(),它将被调用两次 - 可能是令人讨厌且难以调试的崩溃(再次 - 您无法控制时间GC)。 (旁注:一般情况下,这对于Destructors来说确实如此 - 在某些情况下它们可以不止一次被调用!)

#5


0  

See this previous question: Proper use of the IDisposable interface

请参阅上一个问题:正确使用IDisposable接口