Assuming the following:
- A class has managed only members.
- Some members implement
IDisposable
. - The class is
sealed
- a class can't derive from and add unmanaged resources. - The object is used inside a
using
statement - i.eDispose()
is called when done.
There are 3 possible implementations of IDisposable
for this class:
- Minimal
Dispose
method that callsDispose()
onIDisposable
members - NO finalizer. - The standard
IDisposable
implementation with Finalizer BUT missing the usualGC.SuppressFinalize(this)
call inDispose()
. - The full standard
IDisposable
implementation with Finalizer (and withGC.SuppressFinalize(this)
call inDispose()
).
Are the following statements correct? Have I understood this correctly?
- Case A. is has slightly less overhead than B. and C. because the object does not have a finalizer so it does not go in the GCs finalization queue - because of that the GC can clean this object early on in collection - no overhead.
- Case B. the object has a finalizer so will end up in the GCs finalizer queue and the finalizer will get call (because it wasn't suppressed) - the finalizer calls dispose which does nothing because its been called already. This incurs small overhead of object being in finalizer queue and the very small overhead of finalizer call.
- Case C. the object has a finalizer so will still end up in the GCs finalizer queue. Because the dispose and hence
SuppressFinalize
has been called the finalizer won't run. This case still incurs small overhead of the object going in the finalizer queue but the finalizer doesn't actually run.
The key point here that it is tempting to think that "I've avoided the finalizer overhead by calling SuppressFinalize
" - but I think (and would like to clarify) that that is incorrect. The overhead of the object being in the finalizer queue IS still incurred - all you are avoiding is the actual finalizer call - which in the common case is just the "I'm disposed already do nothing".
Note: Here by "Full standard IDisposable
implementation" I mean the standard implementation that is designed to cover both the unmanaged and managed resources case (note here we only have managed object members).
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
private bool _disposed;
protected virtual void Dispose(bool disposing) {
if (_disposed)
return;
if (disposing) {
// dispose managed members...
}
_disposed = true;
}
~AXCProcessingInputs() {
Dispose(false);
}