Here are are few tips on using the IDisposable pattern and using Finalizers
-
Implement IDiposable if accessing managed resources like SQLConnection/Command objects and not disposing them from within the method which instantiates the managed resource
-
Implement Finalizer only if using unmanaged resources (Files, Streams, Windows Handles, Pinvoke) and not disposing them from with the method that instantiates the unmanaged resources
-
Insure that each Type that has a finalizer is responsible for disposing only 1 unmanaged resource, and never reference “reference types” from within a Finalizer
-
Use a protected “disposed” bool within a IDiposable type and check its value in the beginning of each method of that type
-
If a type has a “Open” method which opens a managed resource, then insure that you Implement a Close() method which calls the explicit implementation of IDisposable.Dispose() method
1: public class EncryptedStream : IDisposable
2: {
3: public void Close()
4: {
5: (this as IDisposable).Dispose();
6: }
7:
8: void IDisposable.Dispose()
9: {
10: //Release resources
11: }
12: }
- If the Dispose() method can be called from multiple threads then insure that you use lock(this) before releasing resources. Here is a correct implementation of IDisposable and Finalize pattern which has unmanaged and managed resources to release:
1: public class DisposeType : IDisposable
2: {
3: protected bool disposed;
4: //insure the access modifier is protected so that derived classes can also make use of the same
5: protected virtual void Dispose(bool disposing)
6: {
7: if (disposed)
8: return;
9:
10: lock (this)
11: {
12: if (disposing)
13: {
14: // Release Managed resources here
15: }
16: // Release UnManaged resources here
17: //call the base object's Dispose protected method
18: base.Dispose(disposing);
19: disposed = true;
20: }
21: }
22:
23: public void Dispose()
24: {
25: Dispose(true);
26: GC.SuppressFinalize(this);
27: }
28:
29: ~DisposeType()
30: {
31: Dispose(false);
32: }
33: }
- Compound Finalizable objects: If you have a finalizable object that occupies lot of memory then consider splitting it into 2 classes, one that contains the finalizable object and other that contains the high memory using variables:
1: public class CompoundObject : IDisposable
2: {
3: //this array takes lot of memory
4: int[] array;
5: //instance of inner finalizable object
6: ClipBoardWrapper cwrapper;
7:
8: public CompoundObject(int hwnd, int elements)
9: {
10: array = new int[elements];
11: cwrapper = new ClipBoardWrapper(hwnd);
12: }
13:
14: public void Dispose()
15: {
16: cwrapper.Dispose();
17: }
18:
19: private class ClipBoardWrapper : IDisposable
20: {
21: [System.Runtime.InteropServices.DllImport("user32")]
22: private static extern int OpenClipboard(int hwnd);
23:
24: [System.Runtime.InteropServices.DllImport("user32")]
25: private static extern int CloseClipboard();
26:
27: public ClipBoardWrapper(int hwnd)
28: {
29: OpenClipboard(hwnd);
30: }
31:
32: public void Dispose()
33: {
34: CloseClipboard();
35: GC.SuppressFinalize(this);
36: }
37: ~ClipBoardWrapper()
38: {
39: Dispose();
40: }
41:
42: }
43: }
