IDisposable Interface - disposing managed and unmanaged resources
Hi!
I'm using VS2005 beta 2 and VB. I would like some help on understanding what is the correct way to use the IDisposble interface. After adding the Implements statement, some code is automatically added in the class. In the Dispose(boolean) method, there are two sections to dispose managed and unmanaged resources.
Q1) If a file is opened using one of the System.IO classes, is it considered a managed or unmanaged resource? Should I close the file in the managed or unmanaged dispose section?
Q2) When should I call the dispose method? And if so, should I set the instance of my object to nothing?
Q3) When is Finilize method called?
Q4) If I have another class that holds a collection of a disposable class, should I call the dispose method of all the contained items?
Thanks in advance!
[825 byte] By [
papadi] at [2008-2-15]
1) The classes in System.IO have the unmanaged handle to the file, when you're using them in your own class, they're considered managed. But where you put that code doesn't matter that much.
2) Call the dispose method as soon as you're done with the object. For example, in a method that reads data from a sql server, you set up the connection, open it, execute some command with a data reader and close the connection. All three classes (SqlConnection, SqlCommand, SqlDataReader) implement IDisposable, so the code would be something like:
| |
Try Dim conn As New SqlConnection(connectionString) conn.Open() Try Dim command As New SqlCommand command.CommandText = ... command.Connection = ... Try Dim reader As SqlDataReader = command.ExecuteReader ' read data here Finally reader.Dispose End Try Finally command.Dispose End Try Finally conn.Dispose End Try
|
3. The finalizer gets called by a background thread of the framework on all classes that have a finalizer, unless the class tells it not to by calling GC.SuppressFinalize(this). It is recommended to call this in your Dispose method.
4. If your Dispose method gets called by the finalizer, you should not dispose any other objects. The disposing boolean is used for this - if it's true, it's OK to dispose all other objects in your object.
I suggest you listen to the .NET Rocks! episode #10 with Chris Sells, where he explains the whole system of dispose, finalize and GC in depth for about 15 minutes.
1. Any managed class, ie FileStream, StreamWriter, Stream are managed resources (wrapped around unmanaged resources) so these get disposed in the managed section of the dispose method, things such as COM objects, unmanaged pointers, etc should be disposed in the unmanaged section.
For example:
C#:
| |
protected override void Dispose(bool disposing) { try { if (disposing) { if (_FileStream != null) { _FileStream.Dispose(); _FileStream = null; } } // Free unmanaged COM objects and other unmanaged resources } finally { base.Dispose(disposing); } }
|
VB:
| |
Protected Overrides Sub Dispose(ByVal disposing As Boolean) Try If disposing Then If (Not (_FileStream) Is Nothing) Then _FileStream.Dispose _FileStream = Nothing End If End If ' Free unmanaged COM objects and other unmanaged resources Finally MyBase.Dispose(disposing) End Try End Sub
|
2. You should call the dispose method of an object once you have finished using the object, you can have this done automatically by C# or VB 2.0 by using the using statement, ie:
C#
| |
using (SqlConnection connection = new SqlConnection("...")) { }
|
VB:
| |
Using (connection As New SqlConnection("...")) { }
|
There is no benefit from setting local variables to null or nothing, however it is suggested that instance variables (such as _FileStream above) are set to null in your dispose method.
3. The finalizer is called once the Garbage Collector has determined that an object can no longer be reached (ie no references to it) or when a the environment is shutting down, due to the process ending. It is only called if a derived class actually overrides the default implementation of Object.Finalize and only if GC.SuppressFinalize hasn't been called for the instance (usually called in Dispose()). .NET 1.0/1.1 makes no guarantee when the finalizer will be called, or even if it will be called at all. So finalization should not be relied on and should only be a last resort when Dispose hasn't been called on a object.
4. If the object owns the disposable instances (that is, it is responsible for its deletion) then it should call Dispose and it itself should also be disposable.
I have posted a blog entry containing a class that is the base class of all my disposable objects, it is in C#, however it hopefully should provide an example of how to implement a disposable object:
http://davidkean.net/archive/2004/09/30/172.aspx
Check out this great post by Chris Brumme on Finalization:
http://blogs.msdn.com/cbrumme/archive/2004/02/20/77460.aspx
Also have a look at Applied .NET Framework Programming by Jeffrey Richter, which has a great chapter on how the Garbage Collector works.