Why does the traditional Dispose pattern suppress

2020-04-03 07:38发布

Assuming this as the traditional Dispose pattern (taken from devx but seen on many websites)

class Test : IDisposable
{
  private bool isDisposed = false;

  ~Test()
  {
    Dispose(false);
  }

  protected void Dispose(bool disposing)
  {
    if (disposing)
    {
      // Code to dispose the managed resources of the class
    }

    // Code to dispose the un-managed resources of the class

    isDisposed = true;
  }

  public void Dispose()
  {
    Dispose(true);
    GC.SuppressFinalize(this);
  }
}

I don't understand why we call GC.SupressFinalize(this). This requires me to write my own managed resource disposal, including nulling my references? I'm a bit lost, I must admit. Could someone shed some light on this pattern?

Ideally, I would like to only dispose my unmanaged resources and let the GC do the managed collecting by itself.

Actually, I don't even know why we specify a finalizer. In any case, the coder should call dispose himself, now shouldn't he? If that's just a fallback mechanism, I'd remove it.

6条回答
趁早两清
2楼-- · 2020-04-03 08:12

The SuppressFinalize call exists in case some derived class decides to add a finalizer. If a normal dispose completes successfully, finalization won't be necessary; even if a derived class decides to add one, the SuppressFinalize call will prevent it from executing and interfering with garbage collection.

To understand why this is important, you should think of finalization not as being part of garbage collection, but rather something that happens before it. When a class registers for finalization (automatic on creation, if it overrides Finalize) it is put into a special list called the Finalization Queue. No object in the Finalization Queue, nor any object referenced directly or indirectly by an object in the queue, can be garbage-collected, but if any object in the finalization queue is found to have no rooted references other than from the queue, the object will be pulled from the queue and the finalizer will run. While the finalizer is being dispatched, the object will not be collectable (since a reference will exist during the dispatch); once the finalizer is complete, there will usually not be any references to the object anymore, so it (and objects referenced thereby) will usually be collectable.

Personally, I think the SuppressFinalize is silly, since I can think of no good reason why a derived class should ever have a finalizer. If a derived class is going to add souse unmanaged resources(*) which the parent class will know nothing about, another class should be created for the purpose of holding those resources; the parent class should hold a reference to that. That way, the parent class itself will not need finalization, and objects which are referenced by the parent class won't be needlessly blocked from garbage collection.

查看更多
Melony?
3楼-- · 2020-04-03 08:12
// If the monitor.Dispose method is not called, the example displays the following output:
//       ConsoleMonitor instance....
//       The ConsoleMonitor class constructor.
//       The Write method.
//       The ConsoleMonitor finalizer.
//       The Dispose(False) method.
//       Disposing of unmanaged resources.
//       
// If the monitor.Dispose method is called, the example displays the following output:
//       ConsoleMonitor instance....
//       The ConsoleMonitor class constructor.
//       The Write method.
//       The Dispose method.
//       The Dispose(True) method.
//       Disposing of managed resources.
//       Disposing of unmanaged resources.

From https://msdn.microsoft.com/en-us/library/system.gc.suppressfinalize(v=vs.110).aspx

查看更多
Bombasti
4楼-- · 2020-04-03 08:22

As noted on MSDN executing the Finalize method is costly. By calling dispose you've already self finalized your class so the finalizer doesn't need to be called. The finalizer is implemented in case the Dispose is never called directly by your code (or whoever 'owns' the instance).

查看更多
欢心
5楼-- · 2020-04-03 08:26

The IDisposable pattern is used so that the object can clean up its resources deterministically, at the point when the Dispose method is called by the client code.

The finaliser is only there as a fallback in case the client code fails to call Dispose for some reason.

If the client code calls Dispose then the clean-up of resources is performed there-and-then and doesn't need to be done again during finalisation. Calling SuppressFinalize in this situation means that the object no longer incurs the extra GC cost of finalisation.

And, if your own class only uses managed resources then a finaliser is completely unnecessary: The GC will take care of any managed resources, let those resources themselves worry about whether they need a fallback finaliser. You should only consider a finaliser in your own class if it directly handles unmanaged resources.

查看更多
▲ chillily
6楼-- · 2020-04-03 08:29

SuppressFinalize only suppresses any custom finalizer.

It does not alter any other GC behavior.
You never need to explicitly null out references. (Unless you want them to be collected early)

There is no difference between a class without any finalizer and an instance on which you've called SuppressFinalize.

Calling SuppressFinalize prevents an extra call to Dispose(false), and makes the GC somewhat faster. (finalizers are expensive)

Note that classes without unmanaged resources should not have a finalizer. (They should still call SuppressFinalize, unless they're sealed; this allows inherited classes to add unmanaged resources)

查看更多
相关推荐>>
7楼-- · 2020-04-03 08:34

From Msdn : " This method sets a bit in the object header, which the system checks when calling finalizers. The obj parameter is required to be the caller of this method. Objects that implement the IDisposable interface can call this method from the IDisposable.Dispose method to prevent the garbage collector from calling Object.Finalize on an object that does not require it. "

So it prevents an extra call from the GC. If it is called from within the the finalizer method, when object is being finalized, then it wont do anything, as it is already being finalised. Otherwise, the GC is allowed to reclaim memory, without finalisation of the object, thus making things faster.

查看更多
登录 后发表回答