Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

The Power of Delegates in C#

0.00/5 (No votes)
19 Jun 2013 2  
Document describes about the Delegate in C# and the usage of delegate in different scenarios

Introduction

Hi folks this time I would like to scribble down something on C# features. Most of us (or rather, most intermediate developers) are not exploiting all the features of C#, there are lots of features in C# that we've never heard of or even imagined. Sometimes our ignorance of C#'s capabilities makes us write 100 lines of code instead of a single LOC that might satisfy our requirements more easily, effectively and efficiently. So in this article I would like to explain one of the powerful features of C# delegates.

Delegates

If somebody asks you, what is a delegate? In single line we can say, "A delegate is a function pointer." Or we can say that a delegate is a type or an object which holds a function's reference.

To make a delegate point towards a function we must satisfy the below rule: The function’s signature (which is to be pointed to by a delegate) must be the same as the pointing a delegate’s signature.

Let’s see how a delegate points to a function practically. In this example I am going to create an ASP.NET application to show how to use a delegate. We are all fed up seeing the black screens of console applications in almost all the tutorials and articles we read, so I opted for ASP.NET for our purposes.

I am going to create an application which calculates the area of a circle. 

Looks good right?

Then we are going to write a function to calculate the area in our application.

In the above screen shot you can see the method to calculate the area. You might be thinking, "what’s new in this?" Yes, nothing is new in that :). If we execute the application we will be getting an output area corresponding to the input. Here comes the hero.

There are three steps in defining and using delegates:

  1. Declaration
  2. Instantiation
  3. Invocation

In the above snap shot you can see that I have declared a delegate called DelCalcArea, then inside the button click I have created a delegate object (instantiation) and assigned a method Calculatearea to it. I hope everything up until now is clear. To calculate area we are not calling our CalculateArea method directly from the button click, but we are invoking the delegate to which our method is attached. You can see in the next line we are invoking the DelCalcArea delegate object with the help of the Invoke method (invocation), and you can see one more thing by looking at the tool tip of the Invoke which accepts int variables like our Calculate method and also returns a double value. Then, like any other normal method call, just assigns the delegate call to the label in which we want to display the result.

How's this ... very simple right? One thing you have to note is that we are not calling delegates, but invoking the delegate.

MultiCastingDeligate

You may heard of the term MultiCasting Delegate if you tried read about delegates even once, right? Then what is multi casting? In one line we can answer this question by saying, "Invoking multiple methods in a single line," or "MultyCastDelegate is a linked list of Delegates."

How can we invoke multiple methods or more than one method in one single line of code? To do multicasting we have to assign multiple methods with the same signature to a single delegate. Let’s take an example; I got a requirement like, want to execute 2 methods in a single LOC i.e. one method to calculate area of circle and other to calculate area of square. And also one input value to drive both the methods. So our code will look like:

Looking at the above code you can see that the signature of the delegate and the signature of the methods are matching and that the symbol += is used to attach the function to delegate. Let’s look at the output

Yes, it got executed successfully :) Much as we added functions with the help of +=, we can also remove the added method by the help of -=

Using the same example, let's see how we can remove the added Method from the delegate. From the above example we have two methods added to the delegate, and now I am going to remove the method CalculateSquareArea from the delegate delCalc so the above code will look like this:

See how I removed the method in the above snap shot? So what would our expected output be? The method CalculateSquareArea will not be executed and the result will not be displayed in the output, right?

As expected, the function was not executed and the result was not displayed .

User Control Event Handler  

In the previous section I tried to give you an overall idea of what a delegate is. In this section I am going to say how a delegate is related to an event.

If there is an event then there must be an event handler to handle the event. Delegates are typically necessary when we are using user controls in ASP.NET applications to pull the event arguments to the parent page. Let's take a scenario and work on it.

I would like to create an area calculating application for a circle, and I have also decided to make the area Calculator as a user control. The area calculator consists of one text box to enter the radius of a circle and a button to calculate the area, and the calculated area should be displayed in a label in the parent page, i.e. there is no provision in the User-control to display the result. So the question is, can we get the calculated area in our parent page from the user control?

The answer is yes. We can achieve this with the help of Delegates and Events.

Shall we start creating application? 

First add an ASP.NET Project in your solution; I have added a Project called CsharpFeatures.

In that project I have added one user control called ChildUserControll.ascx

Don’t look at the other Project which you can see in the solution called Calculator; we are not going to use that right now.

Let’s design the UI for the user control as I mentioned before. The UI will look like this:

Let’s go and Plumb the inner side of User Control to take the result out. To make the calculation happen we want an event, right? So here we can do the calculation in our calculate button click event’s event handler. OK then. Do we get the button click event in the parent page in which the user control is consuming? Nooo ... we will not get the event or the output from the user control.

To expose the event of the user control we have to add an additional event in our UserControll. If we are adding an event we want an event handler, right? And if we implement an event handler we want Event arguments, right? So what are all things we have to implement?

We have to implement: Event, Eventhandler and Event arguments. OK, let’s see how we are going to implement all these things and how we are going to make use of delegates.

As I mentioned before, I have already created an .ascx control. Inside the ascx control am going to add an Event:

In the above snap shot I have added the Event called MyEvent, which is inside the class on top of page-load event; this is the event which will be exposed to public or to the aspx pages in which this user control is going to be consumed. Did you notice the type of MyEvent? It’s MyEventHandler. Do you think that is a system defined type? No, it's not. MyEventHandler is a delegate. What we are doing is attaching the event handler called MyEventHandler to the event called MyEvent. So what will be the input params of MyEvent? It will be of the MyEventHandler type, right? :) I hope you know how to declare a delegate. In either case I’ll show you the snap shot so that you can understand it a bit better.


See the delegate? Does its signature look similar to anything you are familiar with? Yes. Just see below the Page_Load event’s parameters, one difference you can see is the EventArgs while in our delegate input it's MyEventArgs. The EventArgs is system defined Event arguments and MyEventArgs is defined by us. So what will be there in MyEventArgs? And what will be the input type of the MyEvent event?

The MyEventArgs will contain the data to be returned from the user control after the execution of the functionality.

So in our example what is the data to be returned? It’s the Area, right?

Next I am going to show the MyEventArgs class. This class must be inherited from the System.EventArgs class. The class consists of one property: area.

The area is of type double. For understanding and simplicity's sake I have started in the reverse order of construction. So what is the right order? First Create MyEventArgs, then go for MyEventHandler, and finally MyEvent which uses all the above three things. I hope you get the point. Here we have created the entire infrastructure that is required, but we didn’t really do anything. But if we didn’t start the calculation and didn’t assign any value to anything without doing this, how we are going to take the result out? Let’s go and do that.

As I said earlier we are taking the result out of the control with the help of MyEventArgs. We have to set the calculated area in to the Area Property of the MyEventArgs for the user control. So go and do that.

So in the above snap shot you can see what I have assigned the calculated Area to the MyEventArgs class. The next thing we have to do is take this result out of the control. But how? To take the result out of the control, the only way is through the event, so call the event with the arguments we have created. Like:

This is how we call the event inside the button click by supplying the EventArgs. I have consumed the control, put a debugger, and executed just to show you what is passing out of the control. In this you can see what the objEventArgs contains. Looks pretty good, right?  

Now am going to tell you how we will consume the .ascx control and get the value displayed in the Label, which we have placed in the Default.aspx page. I hope you know how to place the .ascx control in .aspx page. Just drag and drop the control wherever you want. Then our default page will look as shown below upon executing the control.

Let’s go to the Default.aspx page Page_Load event and make the necessary changes. Once we add the UserControll in to the Parent page what actually happens is the object of the user control is created in that parent page. In the below snap shot you can see this. Here, by adding the ChildUserControll in the page I get the ChildUserControll 1 object.

You can also see the event which we have declared inside the user control in the intellisense of the object. So let’s go and add the event handler for the event in the page.

In the tool tip you will see Press TAB to insert. Hit the tab key two times so VS will create an event handler stub for us. You can also see that the type of event handler that is going to be created is of MyEventHandler type, which is the delegate we created for MyEvent handling. All looks well and good :)

After hitting tab the event handler stub got generated and I started plumbing to get the area displayed in the label in the parent page. Refer to the above snapshot. In the intellisense the Area property is of type double. It’s really amazing, right?

The entire code is shown below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Diagnostics;
 
namespace CsharpFeatures
{
    public partial class _Default : System.Web.UI.Page
    {  
        protected
void Page_Load(object
sender, EventArgs e)
        {
           ChildUserControll1.MyEvent+=new MyEventHandler(ChildUserControll1_MyEvent);
        }
 
        void
ChildUserControll1_MyEvent(object sender, MyEventArgs e)
        {
            lblResult.Text = e.Area.ToString();
        }
 
    }}

Look at the output and check whether the result is getting displayed in the label in the parent page.

Wow! It’s an amazing mechanism, right? Delegates are simply amazing.

OK, here I am going to write one single simple scenario where we can use delegates. Did you ever think of loosely coupling our applications using delegates? Yes, we can also develop loosely coupled applications using delegates to an certain extent. I’ll show how we can do this loose coupling. :)

Did you notice one project in our solution explorer called Calculator? I am going to make use of this project and we are going to create a simple calculator which performs three arithmetical operations like Add, Subtract and Multiply with two input integer values. For this I have created one more project (called calculator) as a layer in our solution itself, and I have written the calculation logic inside the Calculator Layer.

Let’s see how I have written the Calculator Layer. Inside the layer I have created a class called MyCalculator. It is here where I am going to write the calculate logic. So what is the role of decoupling or loosely coupling in a simple calculator? There is a large scope for these terms here. Let's set everything aside and think about how can we create an application like a calculator with two layers I.E. presentation layer and business layer.

We will write three public methods in the Calculator layer then will call the methods from the consuming client according to our operation. This requires the help of an if condition or a switch statement. So if we want to add more functionality to our application, what will we do? We have to go and write a method (say, Divide) in the Calculator layer and again make a change in the consuming application to accommodate the change made in the Calculator layer.

The UI Layer and the Calculator Layer(BLL) is tightly coupled. In addition, the consuming end will eventually know all the methods or operations in the Calculator layer because we are using Public methods. So how can we avoid the situation? There are several different ways to deal with this scenario. I am going to explain how we will do this with the help of delegates.

Let’s look at the UI of the application we are using. Look like below snap shot:

Two text boxes which can be used to enter numeric values and perform arithmetic operations, which displayed in the dropdown. Looks cool.

Let’s go and look in to the Calculator Layer and see what all plumbing I have done. As previously stated, we are going to solve this issue with the help of delegates so we want a delegate for sure and also ensure the access specifier must be private. Then only the Calculator Layer can hide the methods within it, right? So let’s go and see what is there in the Calculator Layer.

So you can see one delegate called DelegateMyCalculator which accepts two integer type input parameters and returns integer type data. You can also see three private methods defined in the class. As the next step let’s go and attach the delegate to the methods. Here is the tricky part, as before we are not directly assigning methods to delegates but creating a method with the return type of delegate (DelegateMyCalculator), which also accepts one string type of input parameter.

So looking at the above snap shot you can see the marked line of code. In the first one the delegate method is called Calculate, which accepts an input parameter of string type, then inside that method we have created an object of the delegate (DelegateMyCalculator) and assigned it to null. You can also clearly see that the assigning to the delegate is done only once, and only to one method according to the input of the Calculate method. Let’s go and consume the method from our UI Layer.

Here is one question which will rock your world: How can we call a delegate method? How can we supply the input values to the delegate method from the UI? The method accepts only one input parameter, right? Go and see the plumbing of UI layer.

What I have done is created an object of the MyCalculator class. Let’s see all the methods the object is displaying in the intellisense:

You can see the method called Calculate which is of type DelegateMyCalculator and is also visible in the tool tip. We don’t have any other methods displayed so the UI will not know all operations are in the Calculator layer (BLL). That’s one intention. We will be passing the operation as a selected value from the drop-down list to the Calculate method.

Next we pass the input parameters to the method. Let's just see what is in the intellisense of Calculate method call.

Here you can see the magic. There is one method called Invoke which accepts two input parameters and both are integer. What will happen if we use this method by passing the values of the textboxes as parameters to Invoke as integer? What will the LOC will look like?

And one more thing I have done is assigned the return value to a label in our UI Layer. Go and execute the application and see what happens.

See? It worked fine 10 + 10= 20; the result is displayed in the label as assigned. We can say that the application is loosely coupled because if we want to add one more functionality, we can go and add one method in the Calculator layer (say, divide) then do a very minute change in the UI I.E. to add one operation (Divide) in the drop-down list. You can add methods in the immediate layer with far less changes in preceding or succeeding layer.

Conclusion

Delegates are really powerful.

Thank you  

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here