问题
I use a default IDisposable implementation template (pattern) for my code.
snippet:
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool isDisposing)
{
if (!this.disposed)
{
if (isDisposing)
{
//cleanup managed resources
}
//cleanup unmanaged resources
this.disposed = true;
}
}
My question: why is the call "GC.SuppressFinalize(this)" in the Dispose public method? I would place "GC.SuppressFinalize(this)" in the "if (isDisposing)" section of the protected method, after disposing managed resources.
Like this:
protected virtual void Dispose(bool isDisposing)
{
if (!this.disposed)
{
if (isDisposing)
{
//cleanup managed resources
GC.SuppressFinalize(this);
}
//cleanup unmanaged resources
this.disposed = true;
}
}
回答1:
I suppose its a clear case of Template Design pattern.
Your abstract class is Designed to take care of all important/necessary tasks required (Here, GC.SuppressFinalize(this)), and allowing a derived class to override only some part of the code.
There are 2 cases here:
Snippet 1, SuppressFinalize, in Dispose
Snippet 2, SuppressFinalize, in Dispose(true)
Here, Snippet 1, makes sure that GC.SuppressFinalize is always executed. While snippet 2, leaves the execution of GC.SuppressFinalize at the mercy of derived class.
So, by putting GC.SuppressFinalize, in Dispose method, you as a designer of your class will always make sure that irrespective of whatever code written by derived classes, GC.SuppressFinalize will be executed.
This is only the benefit of writing SuppressFinalize in Dispose rather then Dispose(true).
回答2:
The Dispose(bool isDisposing)
method isn't part of the IDisposable interface.
You would normally call Dispose(true)
from your Dispose method, and call Dispose(false)
from your finalizer, as a fallback in the case where the object hasn't already been disposed.
Calling SuppressFinalize tells the GC that there's no need to call your object's finalizer, presumably because all your cleanup was done when Dispose
was called.
If you don't have a finalizer on your class, then you don't need to call SuppressFinalize
at all, since there's no finalizer to suppress!
Joe Duffy has some great guidelines on disposal, finalization, garbage collection etc.
回答3:
I think either layout could have been chosen, but probably they wanted to emphasize "put all deallocation code in this method" in the protected Dispose method, so they put the other artifact of disposing (Suppressing finalization) elsewhere.
Also, suppose a derived class had another reason for calling the protected Dispose method, but did still want finalization to occur (for whatever imagined reason, I don't know).
回答4:
Cause .Dispose is when managed code (your code) disposes of the object thereby opting out of finalisation. People usually create another route into Dispose(bool disposing) via a finaliser and the call wouldn't make any sense for the finaliser to make.
回答5:
The idea is that your cleanup code should only be called once. However there are two points of entry: the Dispose
method and object finalizers. When Dispose
is called, you opt-out of finalization so that your cleanup code is only called once. The code here might illustrate it better.
Quote:
// NOTE: Leave out the finalizer altogether if this class doesn't
// own unmanaged resources itself, but leave the other methods
// exactly as they are.
来源:https://stackoverflow.com/questions/605466/idisposable-gc-suppressfinalizethis-location