Why should we call SuppressFinalize when we don't have a destructor

倾然丶 夕夏残阳落幕 提交于 2019-11-27 19:22:31

I'm going out on a limb here, but... most people don't need the full-blown dispose pattern. It's designed to be solid in the face of having direct access to unmanaged resources (usually via IntPtr) and in the face of inheritance. Most of the time, neither of these is actually required.

If you're just holding a reference to something else which implements IDisposable, you almost certainly don't need a finalizer - whatever holds the resource directly is responsible for dealing with that. You can make do with something like this:

public sealed class Foo : IDisposable
{
    private bool disposed;
    private FileStream stream;

    // Other code

    public void Dispose()
    {
        if (disposed)
        {
            return;
        }
        stream.Dispose();
        disposed = true;
    }
}

Note that this isn't thread-safe, but that probably won't be a problem.

By not having to worry about the possibility of subclasses holding resources directly, you don't need to suppress the finalizer (because there isn't one) - and you don't need to provide a way of subclasses customising the disposal either. Life is simpler without inheritance.

If you do need to allow uncontrolled inheritance (i.e. you're not willing to bet that subclasses will have very particular needs) then you need to go for the full pattern.

Note that with SafeHandle from .NET 2.0, it's even rarer that you need your own finalizer than it was in .NET 1.1.


To address your point about why there's a disposing flag in the first place: if you're running within a finalizer, other objects you refer to may already have been finalized. You should let them clean up themselves, and you should only clean up the resources you directly own.

Keep the first version, it is safer and is the correct implementation of the dispose pattern.

  1. Calling SuppressFinalize tells the GC that you have done all the destruction/disposing yourself (of resources held by your class) and that it does not need to call the destructor.

  2. You need the test in case the code using your class has already called dispose and you shouldn't tell the GC to dispose again.

See this MSDN document (Dispose methods should call SuppressFinalize).

Here are the main facts

1) Object.Finalize is what your class overrides when it has a Finalizer. the ~TypeName() destructor method is just shorthand for 'override Finalize()' etc

2) You call GC.SuppressFinalize if you are disposing of resources in your Dispose method before finalization (i.e. when coming out of a using block etc). If you do not have a Finalizer, then you do not need to do this. If you have a Finalizer, this ensures that the object is taken off of the Finalization queue (so we dont dispose of stuff twice as the Finalizer usually calls the Dispose method as well)

3) You implement a Finalizer as a 'fail safe' mechanism. Finalizers are guaranteed to run (as long as the CLR isnt aborted), so they allow you to make sure code gets cleaned up in the event that the Dispose method was not called (maybe the programmer forgot to create the instance within a 'using' block etc.

4) Finalizers are expensive as Types that have finalizers cant be garbage collected in a Generation-0 collection (the most efficient), and are promoted to Generation-1 with a reference to them on the F-Reachable queue, so that they represent a GC root. it's not until the GC performs a Generation-1 collection that the finalizer gets called, and the resources are released - so implement finalizers only when very important - and make sure that objects that require Finalization are as small as possible - because all objects that can be reached by your finalizable object will be promoted to Generation-1 also.

1. Answer for the first question

Basically, you don't have to call SuppressFinalize method if your class doesn't have a finalize method (Destructor). I believe people call SupressFinalize even when there is no finalize method because of lack of knowledge.

2. Answer for the second question

Purpose of the Finalize method is to free un-managed resources. The most important thing to understand is that, Finalize method is called when the object is in the finalization queue. Garbage collector collects all the objects that can be destroy. Garbage Collector adds objects those have got finalization to the finalization queue before destroy. There is another .net background process to call the finalize method for the objects those are in the finalization queue. By the time that background process execute the finalize method, that particular object's other managed reference may have been destroyed. Because there is no specific order when it comes to the finalization execution. So, the Dispose Pattern wants to make sure that finalize method do not try to access managed objects. That's why managed objects are going in side "if (disposing)" clause which is unreachable for the finalize method.

You should always call SuppressFinalize() because you might have (or have in the future) a derived class that implements a Finalizer - in which case you need it.

Let's say you have a base class that doesn't have a Finalizer - and you decided not to call SuppressFinalize(). Then 3 months later you add a derived class that adds a Finalizer. It is likely that you will forget to go up to the base class and add a call to SuppressFinalize(). There is no harm in calling it if there is no finalizer.

My suggested IDisposable pattern is posted here: How to properly implement the Dispose Pattern

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