Click here to Skip to main content
15,890,579 members
Articles / Programming Languages / C#
Article

Understanding Delegates in C#

Rate me:
Please Sign up or sign in to vote.
1.08/5 (11 votes)
2 Nov 20066 min read 28.3K   211   14   1
This tutorial describes some basics about some of the great features of the C# language, namely Delegates and Events.

Introduction

What are Delegates?

We all are familiar with the functions. We know that they perform a predefined set of work and return results based on arguments passed to them. For instances, a function AddOper(a,b) adds two numbers a and b and return the sum of these two numbers. Now think of writing a function which is versatile i.e. it is capable of performing a wide variety of tasks. Say it is capable of adding, subtracting and multiplying numbers.

One way of writing such a function would be to pass the type of operation we want to perform as argument along with the values on which we want to perform our operation. Example:AddOper(a,b,"add") for adding a and b. Inside the function we will be using the Select Case or if else statements for choosing the type of operation we want to perform. This approach is obviously complex and restrictive.

We want a very flexible and generic solution. We want to write a generic function called by the Main Application which in turn calls the appropriate function i.e. we are looking for something like this.

Now, the question is, is it possible to write such flexible Applications?

Yes, it is achievable if we pass a method to a method. Like GenericFun(AddOper). However, C# does not recommend this approach because of type safety reasons. Rather, C# has introduced a new object called DELEGATE for this purpose.

Like Class type, we define Delegate type and then create an instance of delegate to hold the details of a function, note that the instance only contains the details such as function signature and return type and not function body.

The syntax of declaring the delegate is as follows:

Public delegate int GenericFun(int a, int b); 

Essentially, we are saying that delegate will accept functions whose return type is integer and which takes two arguments of type integers.

Now, lets say we want to work with addition function defines as follows:

Private int AddOper(int a,int b){} 

Now, lets create an instance of this delegate and pass our add function to it. GenericFun? gfAdd=new GenericFun(AddOper);

So you see the constructor of a delegate takes the function name.

Now, lets see how we can pass this delegate to a generic function PrintResult? which can operate on any two numbers and returns an integer. Thus it can be used to print the result of Addition, subtraction, multiplication or any type of procedure which takes two integers and returns an integer. Currently, lets see how we can make PrintResult? to add two numbers.

//Define two numbers we want to add
int No1=40; 
int No2=60;

//now call generic function to add these numbers
PrintResult(gfAdd,No1,No2)

You will see 100 on the console.

Now we will see how PrintResult? method is defined.

Private int PrintResult(GenericFun action,int a,int b){
int result=action(a,b);
console.WriteLine(result);
}

so did you notice the magic! Just create an instance of delegate passing it the function you want to work with and then call your generic function passing it the delegate and you are done. To repeat the same exercise with subtraction function, we will do as follows:

GenericFun? gfSub=new GenericFun(SubOper);
PrintResult(gfSub,No1,No2);

However, it is possible to define an array of delegates, rather then defining each separate delegate. Thus we can also do the following:

GenericFun[] gf=new GenericFun(AddOper),
new GenericFun(SubOper),

Then to execute Subtract operation, use the following syntax:
PrintResult(gf1,No1,No2)

OK, Let me walk you through an example which uses Events, to see how delegates can be used with Events. Note that Events are a type of delegates.

To understand what delegates are and how they can be used, lets start with a simple scenario. A bank has a call center, which receives ATM card disputes. After the disputes are settled, the bank Rep sends the customer the outcome of the dispute in one of the following ways:


Email, if an email address is available by clicking SendEmail? button.
Fax, if fax number is available by clicking SendFax? button or
Letter, if email address or fax number is not available by clicking SendLetter? button.

So we need three event handlers to handle one of the following events:
SendEmailEvent? handler
SendFax? Handler,
SendLetter? handler.

We also need a Generic function that is called by the Main Application and which in turns calls appropriate Event Handler.

Lets start by writing three classes, which will be called Email, Fax and Letters respectively. Each class will have its own methods of sending Information. Therefore, Email class will have SendEmailMessage? method, Letter will have SendLetter? and Fax will have SendFax? methods for sending information.

Now, we need another class called MessageWatcher?, which is responsible for invoking the appropriate send method based on user's selection

We will also desigb a form with three buttons each for sending a particular type of message. Now when Rep clicks the SendEmailMessage? button, an event is generated, MessageWatcher? intercepts this event and calls the appropriate Event Handler. In this case the SendEmailMessage? method of Email class. Lets see how this can be done.

Image

The MessageWatcher? class and the generic SendMessage? function is shown below.

//define MessageWatcher class which will send the messages
public class MessageWatcher {

//define messenger delegate
public delegate void MessageHandler(object Sender, MessageInfo mi);

//define an event 
public event MessageHandler OnMessageSendRequest;

//This function is reasponsible of sending the messages
public void SendMessage(MessageInfo mr) {
//make sure it is defined
if  (OnMessageSendRequest !=null)
OnMessageSendRequest(this,mr);
}

Notice that OnMessageSendRequest(this,mr) function is taking two arguments and does not return anything. Compare it with the SendEmailMessage? function as shown below.
public void SendEmailMessage(object Sender,MessageInfo? ei){}

It is extremely important that the signature of all the participating functions along with the generic function should have identical signature. Thus the signature of SendEmailMessage? and OnMessageSendRequest(this,mr) should have matching arguments and return type.

OK, so now the question is, how does MessageWatcher? class determines that it has to invoke the SendEmailMessage? handler? For this, first EmailClass? needs to notify the Watcher class that it will handle the SendEmail? event and it does this in its constructor. The syntax is as follows:

public Email(MessageWatcher mw){

//store watcher reference
watcher=mw;

//tell MessageWatcher that it will handle the SendEmail event
watcher.OnMessageSendRequest+=new 
MessageWatcher.MessageHandler(SendEmailMessage);
}

When the Email class is instantiated, it notifies the MessageWatcher? that when OnMessageSendRequest? event is raised, it will handle the event.
Did you notice that MessageHandler? is the delegate and we are simply passing it the function name SendEmailMessage?. So the Email class is essentially notifying the MessageWatcher? class that it will handle the SendEmailMessage? event.

Finally, in the main application we use these three lines.
//create an instance of email class

MessageWatcher mw=new MessageWatcher();
Email em=new Email(mw);mw.SendMessage(mi);

When the Rep clicks the SendEmailMessage? button, the Main Application create an instance of MessageWatcher? class and Email class. The Email constructor is passed the instance of watcher class. When Email class is instantiated, it notifies the MessageWatcher? instance that it will handle the event which in our case is SendEmailMessage?. Finally, the Main Application calls the generic SendMessage? function of the MessageWatcher? class passing it the MessageInfo? data structure.
The SendMessage? function MessageWatcher? class raises OnMessageSendRequest(this,mr) event and since the Email class has already notified the MessageWatcher? class that it will handle the SendEmailMessage? event therefore SendEmail? function is called to handle this event.

The Email class makes use of .NET System.Web classes for sending emails.

The Letter class makes use of Microsoft Word library. Since this library is a COM component thereforeI have used the System.Runtime.InteropServices. This class uses a template letter which has bookmarks for inserting texts for a customer.

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


Written By
India India
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Questiondelegate.cs missing Pin
Clingfree15-Nov-06 5:32
Clingfree15-Nov-06 5:32 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.