Recently I needed to compare a suggested pattern for IDisposable and object finalization with the auto-generated one we which VS2005/VB.NET provide. We have used the auto-generated one a fair bit, but after looking it the two side by side I had a number of questions about the VB.NET implementation…
For reference, here is the IDE’s implementation:
Public Class Class1 Implements IDisposable Private disposedValue As Boolean = False ''// To detect redundant calls ''// IDisposable Protected Overridable Sub Dispose(ByVal disposing As Boolean) If Not Me.disposedValue Then If disposing Then ''// TODO: free managed resources when explicitly called End If ''// TODO: free shared unmanaged resources End If Me.disposedValue = True End Sub #Region ' IDisposable Support ' ''// This code added by Visual Basic to correctly implement the disposable pattern. Public Sub Dispose() Implements IDisposable.Dispose ''// Do not change this code. Put cleanup code in Dispose(ByVal disposing As Boolean) above. Dispose(True) GC.SuppressFinalize(Me) End Sub #End Region End Class
Questions:
- If Finalize() is called during GC without object.Dispose() being explicitly called first then disposing:=false and the code within ‘if disposing…’ will never execute to free the managed resources–resulting in them remaining in memory until the next GC pass. Why wouldn’t these be explicitly freed? Wouldn’t doing so free more memory on the first GC pass and not leave unneeded objects in memory until the next pass?
- Why doesn’t the IDE generate the Dispose(false) call when overriding Finalize() on an IDisposable class?
- How would the GC know to call Dispose(false) and ensure that it is the IDE’s implementation and not a custom implementation which uses the bool parameter in a different manner? * …and shouldn’t Dispose(disposing as bool) be an interface member if the GC tests for its existence and uses it in a manner that assumes a certain implementation (object.Dispose(disposing:=false))? * In the presence of both
Dispose()andDispose(disposing as boolean)why would the GC ever opt to call the overloaded, non-interface member?
Overall I am confused by the supposed added value of having an extended code-path that executes when Dispose() is called explicitly(as opposed to having a common path that is executed regardless of whether or not Dispose() was called explicitly). While I can appreciate that it is provided with good intentions I can’t see how it does anything other than delay the actual release of managed resources if Dispose() isn’t called directly. In essence it seems to only work to make the managed resources unreachable in the object graph, orphaning them until the 2nd GC run rather than freeing them at a point where they are known to be no longer needed.
Your question has a logical error…if
Dispose()is called within the Finalizer, then yes,disposedValuewill be false, which means thatIf Not Me.disposedValue Then...will execute. The parameter passed fordisposingistrue, so all of the code within there should execute just fine.Edit (turns out the Finalizer calls Dispose(false))
The Finalizer on the form (which only runs if
Dispose()is never called on the Form) invokesDispose(false). The reason for this is that theFormis currently being GC’ed. As a result, MANAGED resources (ie, components on theForm) will get collected and their own Finalizers should invokeDispose()if required. Only unmanaged resources should be released inDispose(false).