Weak Event Pattern

Weak Event Pattern

Incorrect usage of Event can be a reason for Memory leak in c#.Net Application.An event(publisher/Source) keeps a strong reference to its listerner (subscriber/Destination Handler) objects through delegates. This prevents the Garbaggage Collector from freeing up the memory occupied by the listerner when they are not being used.This is perticularly true for the static events which will be present till the lifetime of the application along with the reference to the listener.If the application adds more and more handlers to the events without timily removing or unsubscribing them ,then memory usage will grow till the usage of the application
,till there is no more memory left for allocation.

The solution to the problem is to unsubscribe the event when not being used ,but it is not always obvious to know when you can unsubscribe.Its very difficult to know when an object will be out of scope so that it can unsubscribe to it.

This is where the Weak Event Pattern. It keeps a weak reference for the subscriber in the publishers.That way unsubscribed listeners can be claimed by the garbage collector

The problem without Weak Pattern implementation
===============================================

using System;

public class EventSource
{
        public event EventHandler<EventArgs> Event=delegate {};                //Creating a delegate of type eventhandler
        public void Raise()
        {
                Console.WriteLine("Raise this !!!");
                Event(this,EventArgs.Empty);                        //calling the eventhandler

        }

}

public class EventListener
{
        public int counter {get; set;}                           

        EventSource eventsourceobject;

        public EventListener(EventSource source)
        {
                eventsourceobject=source;
                eventsourceobject.Event += Myhandler;                    //Assigning the handler to the event with the help of delegate
                                            //But this results in string reference and eventually memoery leak
        }

        private void Myhandler(object source,EventArgs args)
        {
                counter++;
                Console.WriteLine("Myhandler recieved event" +counter);            //My handler  only countes the number of times it gets called
        }

        public void UnRegisterEvent()                            // functions which unregisters the event
        {
                eventsourceobject.Event -= Myhandler;
        }
}

public class Program
       {
        public static void Main()
        {
        EventSource source= new EventSource();                        //Creating a source event
        EventListener listener = new EventListener(source);                //creating a listener event
        Console.WriteLine("Raise event first time");               
        Console.Read();
        source.Raise();                                    //Raising and event                           

        Console.WriteLine("\n Set listener to null and call GC");
        Console.Read();

        listener=null;                                    //listener is set to null   
        GC.Collect();                                    //GC is called to get listener
        Console.WriteLine("\n Raise event 2nd time");
        Console.Read();
        source.Raise();                                    //Still listener exists because of stron reference
        Console.ReadKey();
        }


        }

Code With WeakEventManager which establishes weak reference
-------------------------------------------------------------

using System;

public class EventSource
{
        public event EventHandler<EventArgs> Event=delegate {};
        public void Raise()
        {
                Console.WriteLine("Raise this !!!");
                Event(this,EventArgs.Empty);

        }

}

public class EventListener
{
        public int counter {get; set;}

        EventSource eventsourceobject;

        public EventListener(EventSource source)
        {
                eventsourceobject=source;
                eventsourceobject.Event += Myhandler;
        }

        private void Myhandler(object source,EventArgs args)
        {
                counter++;
                Console.WriteLine("Myhandler recieved event" +counter);
        }

        public void UnRegisterEvent()
        {
                eventsourceobject.Event -= Myhandler;
        }
}
using System;

public class EventSource
{
        public event EventHandler<EventArgs> Event=delegate {};
        public void Raise()
        {
                Console.WriteLine("Raise this !!!");
                Event(this,EventArgs.Empty);

        }

}

public class EventListener
{
        public int counter {get; set;}

        EventSource eventsourceobject;

        public EventListener(EventSource source)
        {
                eventsourceobject=source;
                eventsourceobject.Event += Myhandler;
        }

        private void Myhandler(object source,EventArgs args)
        {
                counter++;
                Console.WriteLine("Myhandler recieved event" +counter);
        }

        public void UnRegisterEvent()
        {
                eventsourceobject.Event -= Myhandler;
        }
}
public class WeakEventListener: WeakEventManager
{
        public int counter {get; set;}

        public WeakEventListener(EventSource source)
        {
                WeakEventManager<EventSource , EventArgs>.AddHandler(source,"Event",Myhandler_1);
        }
        private void Myhandler_1(object source,EventArgs args)
        {
                Console.WriteLine("MyHandler_1 recieved event" +counter);
        }


        ~WeakEventListener()
        {
                Console.WriteLine("WeakEventListener Finalized");
        }

}


public class Program
        {
        public static void Main()
        {
        EventSource source= new EventSource();
        //EventListener listener = new EventListener(source);
        WeakEventListener listener_1=new WeakEventListener(source);
        Console.WriteLine("Raise event first time");
        Console.Read();
        source.Raise();

        Console.WriteLine("\n Set listener to null and call GC");
        Console.Read();

        listener=null;
    GC.Collect();
        Console.WriteLine("\n Raise event 2nd time");
        Console.Read();
        source.Raise();
        Console.ReadKey();



        }


        }

Comments

Popular posts from this blog

Authentication and Authorization in Web API -Part1

My Gardening Journey 6