Wednesday, September 13, 2006

IDisposable and finalization code in C# .NET

There is a plenty of errors with finalization and Disposable pattern in code that new C# developers write, that’s why I decided to write about.

When we need to implement a finalizer (destructor)?

The finalization code is incredibly useful when we need to release unmanaged resources. But the problem is that we have no guarantee when the finalization code is called. And because it is not public method the user could not call it explicitly. That is the reason why we need to implement the Disposable pattern. Classes, that don’t need to release unmanaged resources, should not implement a finalizer and IDisposable.

What is the Disposable pattern and when we need to use it?

We need to implement the Disposable pattern only in case when we need to add a finalization code.

The sample of implementation of the Disposable pattern:


class SomeClass : IDisposable
{
// Track whether Dispose has been called.
bool _disposed = false;
object _syncObject = new object();

///
/// When garbage collected, this Finalize method, which
/// will close the unmanaged resource’s handle, is called.
///

~SomeClass()
{
Dispose(false);
}

///
/// Implement IDisposable.
/// Do not make this method virtual.
/// A derived class should not be able to override this method.
///

public void Dispose()
{
// Take yourself off the Finalization queue
// to prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
Dispose(true);
}

///
/// Dispose(bool disposing) executes in two distinct scenarios.
/// If disposing equals true, the method has been called directly
/// or indirectly by a user's code. Managed and unmanaged resources
/// can be disposed.
/// If disposing equals false, the method has been called by the
/// runtime from inside the finalizer and you should not reference
/// other objects. Only unmanaged resources can be disposed.
///

protected virtual void Dispose(bool disposing)
{
lock(_syncObject)
{
if (_disposed)
return;
if (disposing)
{
// The object is being explicitly disposed of/closed, not
// finalized. It is therefore safe for code in this if
// statement to access fields that reference other
// objects because the Finalize method of these other objects
// hasn’t yet been called.
}

_disposed = true;
}
}
}



How to use the objects that implements IDisposable interface:


When you create this kind of object you need to call IDisposable.Dispose() explicitly or implicitly (using statement).

The example of explicit using Dispose:


SomeClass someClassObject = new SomeClass();
// do something with someClassObject
someClassObject.Dispose();

SomeClass yetAnotherObject = new SomeClass();
try
{
// do something with yetAnotherObject
}
finally
{
yetAnotherObject.Dispose();
}


The Dispose should be called to release resources.

The example of implicit using Dispose:

using(SomeClass someClassObject = new SomeClass())
{
// do something with someClassObject
}


In this case Dispose() is called by using statement when we go out of using block.

LandVP LLC

No comments: