The preferred way is to implement IDisposable
along with the dispose pattern. Finalizers are time-limited and the GC will terminate a finalizer if it blocks for too long - this is the primary reason to avoid it where possible.
Dispose
is just a method call and is not time-limited. The dispose pattern optionally features the finalizer for those situations where the caller forgot to call Dispose
(as it's not enforced) as a last-ditch attempt to release resources. The pattern also suppresses the finalizer if dispose was called.
The only valid use I have come across with needing a finalizer was for a series of add-ins I wrote for a third party app that didn't raise relevant events for properly managing object life-times. I used the finalizer to make sure I at least attempted to clean stuff up. Other than this I have never relied upon it directly.
IDisposable
is catered for in C# with the using
keyword. Anything implementing this interface can be used thus:
using (var myDisposableItem = new MyDisposableItem())
{
} // Dispose will be called here for you.
So from the calling perspective this is very simple.
There are various types in the .NET Framework that implement IDisposable
but have nothing to dispose. I always advise acting as if they need disposing directly because the public contract states they have stuff to dispose, even if the implementation doesn't. Don't program to implementation details.