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 existance and uses it in a manner that assumes a certain implementation (object.Dispose(disposing:=false))? * In the presence of both Dispose() and Dispose(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.