-->

09/04/2012

Delegates & Events


In this post, we will go back to basics of C# concepts. From the time when i am new to .Net development till today, one of the first five C# questions is
" What is a Delegate? What is an Event? What are the Differences? "
Lets see this with a practical implementation.

Delegate: It is a type that holds reference of a Method/Function. Simply they can be called as Function Pointers.
In order to create a delegate for a method, both Method and Delegate should have same return type and same set of parameters.

Speaking of delegates we have to know what we can do with delegates.
1. Abstraction of Methods: 
Abstraction is process of hiding the implementation of methods from client. This can also be implemented using delegates. Lets see how.

Step 1: I have 3 simple methods, Add Subtract and Multiply. All accepting 2 Integers and returning Int.
private int Add(int i, int j)
        {
            return i + j;
        }

        private int Substract(int i, int j)
        {
            return i - j;
        }

        private int Multiply(int i, int j)
        {
            return i * j;
        }
Now the client code will be having all the details of what method will be used to do what operation. I don't want to reveal all those detail, for this i created a Delegate to which any of those methods can be assigned.
public delegate int delegateMathMethod(int I, int J);

Step 2: Created a win forms application used for this functionality.
 Step 3: Created a method which will get user input based on which, it will assign the required method.
public delegate int delegateMathMethod(int I, int J);
        private delegateMathMethod ptrMatchMethod;
        public AbstractionDelegate()
        {
            InitializeComponent();
        }

        private void btnCalc_Click(object sender, EventArgs e)
        {          
            lblResult.Text="Result of the Calculation is :"+ GetDelegate().Invoke(Convert.ToInt32(tb1.Text), Convert.ToInt32(tb2.Text)).ToString();            
        }

        private delegateMathMethod GetDelegate()
        {
            int index = rb1.Checked ? 1 : rb2.Checked ? 2 : 3;
            switch (index)
            {
                case 1:
                    ptrMatchMethod = Add;
                    break;
                case 2:
                    ptrMatchMethod = Substract;
                    break;
                case 3:
                    ptrMatchMethod = Multiply;
                    break;
            }
            return ptrMatchMethod;
        }
Above highlighted code will be the client code and which will not be having any details about the method names which it is going to call. Thus abstraction is achieved using delegates.

Now, coming to next interesting topic of Delegate and Event.
We have a win forms application to demonstrate this concept of  delegate and How events emerged out of them.
Lets deep dive into code.
Source Form:
public delegate void dlTransmitToAll(string strMsg);
        public dlTransmitToAll ptrTransmit = null;
        private void SourceForm_Load(object sender, EventArgs e)
        {
            Listner1 objListener1 = new Listner1();
            Listner2 objListener2 = new Listner2();
            objListener1.Show();
            objListener2.Show();
            ptrTransmit += objListener1.ShowMessage;
            ptrTransmit += objListener2.ShowMessage;
        }
        private void btnTransmit_Click(object sender, EventArgs e)
        {
            ptrTransmit.Invoke("Message from Source at " + DateTime.Now.ToShortTimeString());

        }
Listeners:
public void ShowMessage(string msg)
        {
            lblMsg.Text = msg;
        }
Now if you see, the source have all the control, and listeners have to receive the transmitted message irrespective of their interest.
Lets change a bit, try attaching the listeners methods to delegate by passing accessing the delegate from listener code.
If you observe the Listener's code accessing the delegate of source, there is a problem we can see.
Now listener can control everything. It can add more functions to that delegate, it can do any operation that source can do. This is called "Naked Exposure of a Delegate".

Lets look at this situation with a classic example we all know, "Button and Form".
Button is source of the action, and the action will be listened by Form, which will do some task in response. Now button will have a delegate to which form will attach a method of its own to the delegate.
Form shouldn't control the delegate of button and button shouldn't have to decide whether form will listen or not.
This is the situation , where events are evolved.

Events: Events provide a wrapper on delegates thus providing abstraction / encapsulation. Now Listeners will not have full control of action yet listen to it.
 This is how our code will be modified to accommodate events.
Source Form:
namespace TestDelegateEvent
{
    public partial class SourceForm : Form
    {
        public delegate void dlTransmitToAll(string strMsg);
        protected dlTransmitToAll ptrTransmit = null;
        public  event dlTransmitToAll eventTransmitToAll;
        private void SourceForm_Load(object sender, EventArgs e)
        {
            Listner1 objListener1 = new Listner1();
            Listner2 objListener2 = new Listner2();
            objListener1.objSource = this;
            objListener2.objSource = this;
            objListener1.Show();
            objListener2.Show();            
        }
        private void btnTransmit_Click(object sender, EventArgs e)
        {
            //ptrTransmit.Invoke("Message from Source at " + DateTime.Now.ToShortTimeString());
            eventTransmitToAll("Message from Source at " + DateTime.Now.ToShortTimeString());
        }
        public SourceForm()
        {
            InitializeComponent();
        }        
    }
}
Listener1:
namespace TestDelegateEvent
{
    public partial class Listner1 : Form
    {
        public SourceForm objSource;
        public void ShowMessage(string msg)
        {
            lblMsg.Text = msg;
        }
        private void Listener1_Load(object sender, EventArgs e)
        {
            if (objSource != null)
                objSource.eventTransmitToAll += ShowMessage;
        }
        public Listner1()
        {
            InitializeComponent();
        }
    }
}
Listener2:
namespace TestDelegateEvent
{
    public partial class Listner2 : Form
    {
        public SourceForm objSource;
        public void ShowMessage(string msg)
        {
            lblMsg.Text = msg;
        }
        private void Listner2_Load(object sender, EventArgs e)
        {
            if (objSource != null)
                objSource.eventTransmitToAll += ShowMessage;
        }        
        public Listner2()
        {
            InitializeComponent();
        }
    }
}
The above highlighted code in Listeners is responsible for subscribing event from Source.
So the main difference is that event provides one more level of encapsulation over delegates, and we have demonstrated it.

Hope i made myself clear.
Code:
Click Here
Is it helpful for you? Kindly let me know your comments / Questions.

3 comments: