Where to call Dispose()
for IDisposable
objects owned by an object?
public class MyClass
{
public MyClass()
{
log = new EventLog { Source = "MyLogSource", Log = "MyLog" };
FileStream stream = File.Open("MyFile.txt", FileMode.OpenOrCreate);
}
private readonly EventLog log;
private readonly FileStream stream;
// Other members, using the fields above
}
Should I implement Finalize()
for this example? What if I do not implement anything at all? Will there be any problems?
My first thought was that MyClass
should implement IDisposable
. But the following statement in an MSDN article confused me:
Implement IDisposable only if you are using unmanaged resources directly. If your app simply uses an object that implements IDisposable, don't provide an IDisposable implementation.
Is this statement wrong?
Rule#1: Properly dispose of classes that implement IDisposable. The first rule is whenever you are consuming a class that implements the IDisposable interface; you should call the “Dispose” method when you are done with that class.
public void Dispose() { Dispose(disposing: true); // This object will be cleaned up by the Dispose method. // Therefore, you should call GC. SuppressFinalize to // take this object off the finalization queue // and prevent finalization code for this object // from executing a second time.
The Dispose() methodThe Dispose method performs all object cleanup, so the garbage collector no longer needs to call the objects' Object. Finalize override. Therefore, the call to the SuppressFinalize method prevents the garbage collector from running the finalizer. If the type has no finalizer, the call to GC.
Dispose() will not be called automatically. If there is a finalizer it will be called automatically. Implementing IDisposable provides a way for users of your class to release resources early, instead of waiting for the garbage collector.
If MyClass
owns an IDisposable
resource, then MyClass
should itself be IDisposable
, and it should dispose the encapsulated resource when Dispose()
is called on MyClass
:
public class MyClass : IDisposable {
// ...
public virtual void Dispose() {
if(stream != null) {
stream.Dispose();
stream = null;
}
if(log != null) {
log.Dispose();
log = null;
}
}
}
No, you should not implement a finalizer here.
Note: an alternative implemention might be something like:
private static void Dispose<T>(ref T obj) where T : class, IDisposable {
if(obj != null) {
try { obj.Dispose(); } catch {}
obj = null;
}
}
public virtual void Dispose() {
Dispose(ref stream);
Dispose(ref log);
}
For objects containing other IDisposable
objects, it's a good and recommended practice to implement IDisposable
on your own object, so others consuming your type can wrap it in a using
statement:
public class MyClass : IDisposable
{
public MyClass()
{
log = new EventLog { Source = "MyLogSource", Log="MyLog" };
FileStream stream = File.Open("MyFile.txt", FileMode.OpenOrCreate);
}
private readonly EventLog log;
private readonly FileStream stream;
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// Free managed objects here
stream.Dispose();
}
}
// Other members, using the fields above
}
In your case, you aren't freeing up any managed resources so no finalizer is needed. If you were, then you would implement a finalizer and call Dispose(false)
, indicating to your dispose method that it is running from the finalizer thread.
If you don't implement IDisposable
, you're leaving it up to the GC to clean up the resources (e.g, close the Handle
on the FileStream
you've opened) once it kicks in for collection. Lets say your MyClass
object is eligible for collection and is currently in generation 1. You would be leaving your FileStream
handle open until the GC cleans up the resource once it runs. Also, many implementations of Dispose
call GC.SuppressFinalize
to avoid having your object live another GC cycle, passing from the Initialization Queue to the F-Reachable queue.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With