none
Disposing a custom class RRS feed

  • Question

  • Hello i have a custom class (Class A) . this class has some events....... i have another class (Class B) that has an instance of Class A, class B subscribes to the events in CLass A. when i call Dispose() on Class B should i unsubscribe from the events of the instance of Class A and then call the dispose of class A. or should the dispose of Class A set its events to null? what is the best approach? and what is the best way to unsubscribe all subscriptions of an event?

    Thanks to all in advance.

    • Moved by Annabella Luo Tuesday, March 27, 2012 4:28 AM (From:Windows Presentation Foundation (WPF))
    Monday, March 26, 2012 1:45 AM

Answers

  • Hi, 

    Few of my words, 

    From your explanation, i understand classes are like

    public class ClassA
            {
                public event EventHandler CustomEvent;
            }
    
    public class ClassB
            {
                ClassA a = new ClassA();
                public ClassB()
                {
                    a.CustomEvent += Perform;
                }
    
                public void Perform(object sender, EventArgs e)
                {
                }
            }
     

    a.CustomEvent += Perform, means object a holds the reference of object b

    when you set b = null, on call to GC.Collect, object a also garbaged, so no need to explicitly unwire. This is the result what Adavesh is showing above.

    What scenarios we need to consider for unwire?

    Consider following scenario,

        class Program
        {
            static void Main(string[] args)
            {
                Debug.WriteLine(GC.GetTotalMemory(false)); //669100 bytes
    
                var a = new ClassA();
                var b = new ClassB();
                Debug.WriteLine(GC.GetTotalMemory(false)); //1010052 bytes
    
                b.CustomEvent += a.PerformSomeAction;
    
                GC.Collect(); //just make sure clean any other references
                Debug.WriteLine(GC.GetTotalMemory(false)); //483680 bytes
    
                // b.CustomEvent -= a.PerformSomeAction;
                a = null;
                GC.Collect();
                Debug.WriteLine(GC.GetTotalMemory(false)); with out unwire size is //481232 bytes
    				with unwire size is (uncomment b.CustomEvent...) size is 261144 bytes
                Console.ReadKey();
            }
    
            public class ClassA
            {
                StringBuilder builder = new StringBuilder(110000);
                public void PerformSomeAction(object sender, EventArgs e)
                {
                }
            }
    
            public class ClassB
            {
                public event EventHandler CustomEvent;
    
                public void Perform(object sender, EventArgs e)
                {
                    
                }
            }
        }

    I hope this helps you understand...


    If this post answers your question, please click "Mark As Answer". If this post is helpful please click "Mark as Helpful".


    • Edited by Kris444 Tuesday, March 27, 2012 12:47 PM
    • Marked as answer by salserito6780 Saturday, March 31, 2012 8:46 PM
    Tuesday, March 27, 2012 8:22 AM
  • A class should implement the disposable pattern whenever it holds disposable data.  So yes, you should dispose of the object of type Class A when disposing the object of type Class B, so long the object of type Class A is considered to be an exclusive resource of the object being disposed (of type Class B).  To disconnect from an event, you do:

    classAObject.TheEvent -= new TheEventHandlerType(TheHandlerFunction);


    Jose R. MCP

    • Marked as answer by salserito6780 Saturday, March 31, 2012 8:46 PM
    Tuesday, March 27, 2012 4:32 AM
  • Hi, 

    Yes, setting TheEvent = null, removes all references it holds.

    How do we see this?

    Take the same example as we had, I am using Ants Memory profiler to profile it,

    public class ClassA { public event EventHandler CustomEvent; public void FireEvent() { if (CustomEvent != null) CustomEvent(this, EventArgs.Empty); }

      public void SetEventToNull()
            {
                CustomEvent = null;
            }

    } public class ClassB { ClassA a; public ClassB(ClassA a) { this.a = a; this.a.CustomEvent += new EventHandler(a_CustomEvent); } void a_CustomEvent(object sender, EventArgs e) { MessageBox.Show("Hello"); } }

    and a call to it like,

     public Form1()
            {
                InitializeComponent();
                a = new ClassA();
                b = new ClassB(a);
                button2.Click += new EventHandler(button2_Click);
            }
    
            void button2_Click(object sender, EventArgs e)
            {
                b = null;
                GC.Collect();
            }

    For this scenario profiler shows ClassB is not collected , though you set b = null as shown,

    Then I changed the call to like, 

     void button2_Click(object sender, EventArgs e)
            {
                a.SetEventToNull();
                b = null;
                GC.Collect();
            }

    This resulted, 

    But this is not best practice to do. You should always make sure event handlers are un-wired using -=.

    Since, there might be another place wire up should have happen and by doing this way you will see unexpected results.

    I hope this helps you...


    If this post answers your question, please click "Mark As Answer". If this post is helpful please click "Mark as Helpful".


    • Edited by Kris444 Monday, April 2, 2012 4:15 PM
    • Marked as answer by salserito6780 Saturday, April 14, 2012 8:56 PM
    Monday, April 2, 2012 11:08 AM

All replies

  • Hi salserito6780,

    Thank you for your post.

    According to your description, I think your issue is about CLR, so I'm moving this thread to CLR forum for better support.

    Thank you for your understanding.

    Have a nice day.


    Annabella Luo[MSFT]
    MSDN Community Support | Feedback to us

    Tuesday, March 27, 2012 4:27 AM
  • A class should implement the disposable pattern whenever it holds disposable data.  So yes, you should dispose of the object of type Class A when disposing the object of type Class B, so long the object of type Class A is considered to be an exclusive resource of the object being disposed (of type Class B).  To disconnect from an event, you do:

    classAObject.TheEvent -= new TheEventHandlerType(TheHandlerFunction);


    Jose R. MCP

    • Marked as answer by salserito6780 Saturday, March 31, 2012 8:46 PM
    Tuesday, March 27, 2012 4:32 AM
  • I had also the same knowledge of delegates are prone to memory leak when there are subscribers to a delegate. But just wanted to confirm, so wrote a small program.

    class A
    {
        public event EventHandler Ev;
    }
    class B
    {
        long[] arr = new long[10000];
        long[] arr1 = new long[10000];
        long[] arr2 = new long[10000];
        A a = new A();
        public B()
        {
            a.Ev += (s, e) => { };
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            B objB = new B();
            long gen = GC.GetTotalMemory(false);  // My Result 424940 bytes
            objB = null;
            GC.Collect(0);
            gen = GC.GetTotalMemory(false);        // My Result 105440 bytes
        }
    }
    So, I am not unsubscribing the events. But setting the objB to NULL does clean the memory when GC runs (I verified through CLRProfiler to check existance of objB after Setting it to NULL and after GC). So, what I conclude is that since Object of A is contained within B, setting objB will not keep objB in memory even if you have not unsubscribed the events.

    Please mark this post as answer if it solved your problem. Happy Programming!

    Tuesday, March 27, 2012 6:40 AM
  • Hi, 

    Few of my words, 

    From your explanation, i understand classes are like

    public class ClassA
            {
                public event EventHandler CustomEvent;
            }
    
    public class ClassB
            {
                ClassA a = new ClassA();
                public ClassB()
                {
                    a.CustomEvent += Perform;
                }
    
                public void Perform(object sender, EventArgs e)
                {
                }
            }
     

    a.CustomEvent += Perform, means object a holds the reference of object b

    when you set b = null, on call to GC.Collect, object a also garbaged, so no need to explicitly unwire. This is the result what Adavesh is showing above.

    What scenarios we need to consider for unwire?

    Consider following scenario,

        class Program
        {
            static void Main(string[] args)
            {
                Debug.WriteLine(GC.GetTotalMemory(false)); //669100 bytes
    
                var a = new ClassA();
                var b = new ClassB();
                Debug.WriteLine(GC.GetTotalMemory(false)); //1010052 bytes
    
                b.CustomEvent += a.PerformSomeAction;
    
                GC.Collect(); //just make sure clean any other references
                Debug.WriteLine(GC.GetTotalMemory(false)); //483680 bytes
    
                // b.CustomEvent -= a.PerformSomeAction;
                a = null;
                GC.Collect();
                Debug.WriteLine(GC.GetTotalMemory(false)); with out unwire size is //481232 bytes
    				with unwire size is (uncomment b.CustomEvent...) size is 261144 bytes
                Console.ReadKey();
            }
    
            public class ClassA
            {
                StringBuilder builder = new StringBuilder(110000);
                public void PerformSomeAction(object sender, EventArgs e)
                {
                }
            }
    
            public class ClassB
            {
                public event EventHandler CustomEvent;
    
                public void Perform(object sender, EventArgs e)
                {
                    
                }
            }
        }

    I hope this helps you understand...


    If this post answers your question, please click "Mark As Answer". If this post is helpful please click "Mark as Helpful".


    • Edited by Kris444 Tuesday, March 27, 2012 12:47 PM
    • Marked as answer by salserito6780 Saturday, March 31, 2012 8:46 PM
    Tuesday, March 27, 2012 8:22 AM
  • Hi guys thanks for the replies, they were very helpful. Another question.... lets say on ClassA dispose method i set its events to null would that eliminate the need to unsuscribe from classA events when i call dispose on classB ? so what im saying is that if i can eliminate this from the dispose method of ClassB ?

    classAObject.TheEvent -= new TheEventHandlerType(TheHandlerFunction);

    and just call

    classAobject.Dispose();

    and in classA dispose method just do this....... TheEvent = null; ??

    Saturday, March 31, 2012 8:50 PM
  • Hi guys thanks for the replies, they were very helpful. Another question.... lets say on ClassA dispose method i set its events to null would that eliminate the need to unsuscribe from classA events when i call dispose on classB ? so what im saying is that if i can eliminate this from the dispose method of ClassB ?

    classAObject.TheEvent -= new TheEventHandlerType(TheHandlerFunction);

    and just call

    classAobject.Dispose();

    and in classA dispose method just do this....... TheEvent = null; ??

    Saturday, March 31, 2012 8:50 PM
  • Hi, 

    Yes, setting TheEvent = null, removes all references it holds.

    How do we see this?

    Take the same example as we had, I am using Ants Memory profiler to profile it,

    public class ClassA { public event EventHandler CustomEvent; public void FireEvent() { if (CustomEvent != null) CustomEvent(this, EventArgs.Empty); }

      public void SetEventToNull()
            {
                CustomEvent = null;
            }

    } public class ClassB { ClassA a; public ClassB(ClassA a) { this.a = a; this.a.CustomEvent += new EventHandler(a_CustomEvent); } void a_CustomEvent(object sender, EventArgs e) { MessageBox.Show("Hello"); } }

    and a call to it like,

     public Form1()
            {
                InitializeComponent();
                a = new ClassA();
                b = new ClassB(a);
                button2.Click += new EventHandler(button2_Click);
            }
    
            void button2_Click(object sender, EventArgs e)
            {
                b = null;
                GC.Collect();
            }

    For this scenario profiler shows ClassB is not collected , though you set b = null as shown,

    Then I changed the call to like, 

     void button2_Click(object sender, EventArgs e)
            {
                a.SetEventToNull();
                b = null;
                GC.Collect();
            }

    This resulted, 

    But this is not best practice to do. You should always make sure event handlers are un-wired using -=.

    Since, there might be another place wire up should have happen and by doing this way you will see unexpected results.

    I hope this helps you...


    If this post answers your question, please click "Mark As Answer". If this post is helpful please click "Mark as Helpful".


    • Edited by Kris444 Monday, April 2, 2012 4:15 PM
    • Marked as answer by salserito6780 Saturday, April 14, 2012 8:56 PM
    Monday, April 2, 2012 11:08 AM
  • Thank you very much kriss very good post. helped me understand things alot better.
    Saturday, April 14, 2012 8:56 PM