What is the difference between using IDisposable vs a destructor in C#?

余生颓废 提交于 2019-11-26 12:45:29
Marc Gravell

A finalizer (aka destructor) is part of garbage collection (GC) - it is indeterminate when (or even if) this happens, as GC mainly happens as a result of memory pressure (i.e. need more space). Finalizers are usually only used for cleaning up unmanaged resources, since managed resources will have their own collection/disposal.

Hence IDisposable is used to deterministically clean up objects, i.e. now. It doesn't collect the object's memory (that still belongs to GC) - but is used for example to close files, database connections, etc.

There are lots of previous topics on this:

Finally, note that it is not uncommon for an IDisposable object to also have a finalizer; in this case, Dispose() usually calls GC.SuppressFinalize(this), meaning that GC doesn't run the finalizer - it simply throws the memory away (much cheaper). The finalizer still runs if you forget to Dispose() the object.

The role of the Finalize() method is to ensure that a .NET object can clean up unmanaged resources when garbage collected. However, objects such as database connections or file handlers should be released as soon as possible, instead on relying on garbage collection. For that you should implement IDisposable interface, and release your resources in the Dispose() method.

There is a very good description on MSDN:

The primary use of this interface is to release unmanaged resources. The garbage collector automatically releases the memory allocated to a managed object when that object is no longer used. However, it is not possible to predict when garbage collection will occur. Furthermore, the garbage collector has no knowledge of unmanaged resources such as window handles, or open files and streams.

Use the Dispose method of this interface to explicitly release unmanaged resources in conjunction with the garbage collector. The consumer of an object can call this method when the object is no longer needed.

The only thing that should be in a C# destructor is this line:

Dispose(False);

That's it. Nothing else should ever be in that method.

Your question regarding whether or not you should always call Dispose is usually a heated debate. See this blog for an interesting perspective from respected individuals in the .NET community.

Personally, I think Jeffrey Richter's position that calling Dispose is not mandatory is incredibly weak. He gives two examples to justify his opinion.

In the first example he says calling Dispose on Windows Forms controls is tedious and unnecessary in mainstream scenarios. However, he fails to mention that Dispose actually is called automatically by control containers in those mainstream scenarios.

In the second example he states that a developer may incorrectly assume that the instance from IAsyncResult.WaitHandle should be aggressively disposed without realizing that the property lazily initializes the wait handle resulting in an unnecessary performance penalty. But, the problem with this example is that the IAsyncResult itself does not adhere to Microsoft's own published guidelines for dealing with IDisposable objects. That is if a class holds a reference to an IDisposable type then the class itself should implement IDisposable. If IAsyncResult followed that rule then its own Dispose method could make the decision regarding which of its constituent members needs disposing.

So unless someone has a more compelling argument I am going to stay in the "always call Dispose" camp with the understanding that there are going to be some fringe cases that arise mostly out of poor design choices.

It's pretty simple really. I know it's been answered but I'll try again but will try to keep it as simple as possible.

A destructor should generally never be used. It is only run .net wants it to run. It will only run after a garbage collectoin cycle. It may never actually be run during the lifecycle of your application. For this reason, you should not ever put any code in a destructor that 'must' be run. You also can't rely on any existing objects within the class to exist when it runs (they may have already been cleaned up as the order in which destructors run in is not garanteed).

IDisposible should be used whenever you have an object that creates resources that need cleaning up (ie, file and graphics handles). In fact, many argue that anything you put in a destructor should be putin IDisposable due to the reasons listed above.

Most classes will call dispose when the finalizer is executed but this is simply there as a safe guard and should never be relied upon. You should explicitly dispose anything that implements IDisposable when you're done with it. If you do implement IDisposable, you should call dispose in finalizer. See http://msdn.microsoft.com/en-us/library/system.idisposable.aspx for an example.

Here is another fine article which clears up some of the mist surrounding IDisposable, the GC and dispose.

Chris Lyons WebLog Demystifying Dispose

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!