Using Rx for Event subscription

I thought I would have a quick look to determine wether Rx would create a strong reference under the hood or not when one object subscribed to another objects events. In this case the Consumer object subscribes to the SampleData objects's SampleDataChanged event. This type of strong reference causes memory leaks in applications because the garbage collector will not clean up the event consumer even though the consumer may be out of scope. The result of my testing indicates that unfortunately there is still a strong reference because once the Consumer object goes out of scope and once Garbage collection has been called, calling the event on SampleData still causes the event to be raised in the Consumer meaning that the consumer has not been garbage collected. Can I use the System.WeakReference object to resolve this issue? I will follow up on this shortly...


using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace WeakReferenceTestConsole

{

    class Program

    {

 

        static void Main(string[] args)

        {

 

            SampleData sampleData = new SampleData();

 

            for (int i = 0; i < 3; i++)

            {

                WorkOnData(sampleData, i);

            }

 

            sampleData.RaiseSampleDataChanged("Sample Data change - Consumer outside scope");

 

            // Force garbage collection

            GC.Collect();

            GC.WaitForPendingFinalizers();

 

            sampleData.RaiseSampleDataChanged("Sample Data change - Consumer outside scope - After garbage collection");

 

            Console.ReadKey();

        }

 

        private static void WorkOnData(SampleData sampleData, int iteration)

        {

            // Create a consumer which registers a method with the sample data objects SampleDataChanged event

            Consumer consumer = new Consumer(sampleData);

            consumer.Name = "Consumer " + iteration.ToString();

 

            //Raise the sample data object's data changed event

            sampleData.RaiseSampleDataChanged("Work on data - iteration : " + iteration.ToString());

        }

 

    }

 

    public class Consumer

    {

 

        //private SampleData _sampleData;

 

        public Consumer(SampleData sampleData)

        {

            //_sampleData = sampleData;

            //sampleData.SampleDataChanged += new SampleData.SampleDataChangedEventHandler(Consumer_SampleDataChanged);

 

            Observable.FromEvent<SampleDataChangedEventArgs>(sampleData, "SampleDataChanged").Subscribe(

                args =>

                Consumer_SampleDataChanged(sampleData, (SampleDataChangedEventArgs)args.EventArgs)

                );

 

        }

 

        public string Name { get; set; }

 

        void Consumer_SampleDataChanged(object sender, SampleDataChangedEventArgs e)

        {

            Console.WriteLine("Sample Data Changed : {0} - Notified Consumer : {1}", e.Message, this.Name);

        }

 

        ~Consumer()

        {

            Console.WriteLine("Consumer finalizer");

        }

    }

 

    public class SampleData

    {

        public event SampleDataChangedEventHandler SampleDataChanged;

        public delegate void SampleDataChangedEventHandler(object sender, SampleDataChangedEventArgs e);

 

        public void RaiseSampleDataChanged(string message)

        {

            SampleDataChangedEventHandler handler = SampleDataChanged;

 

            if (handler != null)

            {

 

                SampleDataChangedEventArgs e = new SampleDataChangedEventArgs(message);

                SampleDataChanged(this, e);

            }

 

        }

 

    }

 

    public class SampleDataChangedEventArgs : EventArgs

    {

        public SampleDataChangedEventArgs(string message)

        {

            this.Message = message;

        }

 

        public string Message { get; set; }

    }

 

 

}

 

 

 
Published 05 June 2010 00:39 by jean

Comments

No Comments

Leave a Comment

(required) 
(required) 
(optional)
(required)