Sunday, May 2, 2010

Dispose Complete Hierarchy


While working with a family hierarchy of a class, I was trying to optimize the memory usage because there was a case reported in one of the tools that worked on that the data loaded in memory was using up all the RAM. I worked on the case and found that the custom classes that were written for the project were not disposable. This leaves memory freeing job to Garbage Collector, and its not best decision sometimes.

I wrote two classes for making disposing of objects easy. NayanTools.Dispose method is the core of disposing engine.

One thing that you need to keep in mind while using this function, it will dispose the member objects of the object you pass to it, as well as, it will go in recursion - provided all those classes are implemented from AbstractDisposingClass.

So, the implementation of a disposable class using AbstractDisposingClass should look like -

01 class A : AbstractDisposingClass {
02 ~A() {
03 dispose(false);
04 }
05 };


The usage is simple, as you dispose any other class-
A n = new A();
n.Dispose();


A bit more complex example will be -
01 class A : AbstractDisposingClass {
02 List<string> jjj = new List<string>();
03 ~A() {
04 dispose(false);
05 }
06 };
07
08 class B : AbstractDisposingClass {
09 string test = string.Empty;
10 List<string> hello = new List<string>();
11 List<A> allo = new List<A>();
12 Dictionary<int, int> ddd = new Dictionary<int, int>();
13 public B() {
14 allo.Add(new A());
15 }
16 ~B() {
17 dispose(false);
18 }
19 };
20
21 ...
22
23 private void destroyExample () {
24 B n = new B();
25 n.Dispose();
26 }


Here is the code for the classes and methods.


01 using System.Collections;
02 using System.Reflection;
03 ...
04 public static class NayanTools {
05 public static bool IsList (object obj) {
06 IList list = obj as IList;
07 return list != null;
08 }
09
10 public static bool IsCollection (object obj) {
11 ICollection coll = obj as ICollection;
12 return coll != null;
13 }
14
15 public static bool IsDictionary (object obj) {
16 IDictionary dictionary = obj as IDictionary;
17 return dictionary != null;
18 }
19
20 public static void Dispose (bool bNotDisposed, object _object) {
21 if (bNotDisposed && _object != null) {
22 Type type = _object.GetType ();
23 FieldInfo[] arrayFI = type.GetFields (BindingFlags.FlattenHierarchy|BindingFlags.GetField|BindingFlags.Instance|BindingFlags.NonPublic|BindingFlags.Public);
24 foreach (FieldInfo fieldInfo in arrayFI) {
25 object fieldObject = fieldInfo.GetValue (_object);
26 if (fieldObject != null) {
27 if (NayanTools.IsDictionary (fieldObject)) { //key-value type collection?
28 IDictionary dictionary = fieldObject as IDictionary;
29 foreach (object _ob in dictionary.Values) {
30 if (_ob is IDisposable && _ob != null) {
31 IDisposable _disposeableObj_ = _ob as IDisposable;
32 _disposeableObj_.Dispose ();
33 }
34 }
35 dictionary.Clear ();
36 }
37 else {//normal collection
38 if (NayanTools.IsCollection (fieldObject)) {
39 ICollectioncoll = fieldObject as ICollection;
40 foreach (object _ob in coll) {
41 if (_ob is IDisposable && _ob != null) {
42 IDisposable _disposeableObj_ = _ob as IDisposable;
43 _disposeableObj_.Dispose ();
44 }
45 if (NayanTools.IsList (fieldObject)) {
46 IList list = fieldObject as IList;
47 list.Clear ();
48 }
49 }
50 }
51 }
52 if (fieldObject is IDisposable) {
53 IDisposable _disposeableObj = fieldObject as IDisposable;
54 _disposeableObj.Dispose ();
55 }
56 fieldInfo.SetValue (_object, null);
57 }
58 }
59 }
60 }
61 }
62
63 [Serializable]
64 public abstract class AbstractDisposingClass : IDisposable {
65 [field:NonSerialized]
66 protected bool m_IsDisposed = false;
67
68 public virtual void Dispose () {
69 dispose (true);
70 GC.SuppressFinalize (this);
71 }
72
73 protected virtual void dispose (bool bNotDisposed) {
74 if (!m_IsDisposed) {
75 m_IsDisposed = true;
76 NayanTools.Dispose (bNotDisposed, this);
77 }
78 }
79 }

No comments:

Post a Comment

Talk to me :)