-
Notifications
You must be signed in to change notification settings - Fork 129
Implement IDisposable
jbe2277 edited this page Sep 24, 2023
·
13 revisions
The primary use of the IDisposable
interface is to release unmanaged resources. But it can also be useful for some managed-only cleanup (e.g. removing of event handlers). The usage of this interface is quite attractive because of the using
C# keyword.
The Dispose Pattern provides a good introduction on how to implement the interface and how to use it. This article provides some extended guidelines and some minor adaptions of the MSDN description.
-
Avoid to implement the finalizer (C# destructor) because of performance reasons.
- The finalizer is only needed if the class is directly responsible for releasing unmanaged resources.
- Prefer the
SafeHandle
class for handling unmanaged resources.
-
Do Not throw exceptions in the dispose implementation.
- A finalizer (C# destructor) might call
Dispose
. The finalizer is called by the Garbage Collector. An exception must not be thrown here. - The
using
C# keyword hides theDispose
call and therefore an exception is not expected here. - Furthermore,
Dispose
might be called from infrastructure code like IoC Containers which do not know how to handle exceptions which are thrown during disposing objects.
- A finalizer (C# destructor) might call
-
Consider that the
Dispose
method might be called more than once.- Ignore subsequent
Dispose
calls instead of throwing theObjectDisposedException
.
- Ignore subsequent
- Consider thread-safety because finalizers are called by a separate Thread.
-
Keep care when the method gets called by the finalizer (disposing is false).
- In this case do not access other objects. These objects might already be finalized because the garbage collector disposes them in an unpredictable order.
public class SampleClass : IDisposable
{
// Consider thread-safety because finalizers are called by a separate Thread.
private int isDisposed;
public void Dispose()
{
GC.SuppressFinalize(this);
Dispose(true);
}
protected bool IsDisposed => isDisposed != 0;
// Call this method from a subclass when you implement a finalizer (destructor).
protected void Dispose(bool disposing)
{
if (Interlocked.CompareExchange(ref isDisposed, 1, 0) != 0) return;
OnDispose(disposing);
if (disposing)
{
// Cleanup and call Dispose on objects for which this class is responsible
// here ...
}
// Free unmanaged resources here ...
}
// Override this method in a subclass to free, release or reset any resources.
protected virtual void OnDispose(bool disposing) { }
}