Delegates: Part I

Introduction

Delegate is a reference type just like other object. When you create an object, the memory is allocated for the object on the heap and reference for it is stored in the reference variable, which is in the stack. Consider the below statement:

Here, the organization object is created on the Heap memory and a reference to that memory location is stored on the stack identified by the token Org. Like the Org reference, the delegate reference type will refer to the function address. At runtime the function will be loaded into a code segment of memory like Heap Segment for object created using new keyword. If we take the starting address of the function (First line of translated code) in the Code segment and store it in a reference variable we call that reference variable a Delegate.

Declaring a Delegate

Below is the syntax for declaring a delegate:

<Scope> delegate <returntype> DelegateName(<Parameters>);

In the above Syntax:-

Scope: It is access specification like public, private etc.,

delegate: keyword

returntype: Function return type

DelegateName: Name of the delegate.

Parameters : Function parameter names with types.

Once delegate is declared, you can create the instance of the delegates. Just think about the class below:

class Publishers {}

The class keyword is used to specify the token Publishers as a class template. Later, you can create the object of template type Publishers. The same holds true for delegates. The above syntax just shows how to declare a delegate. Consider the below example for the syntax:

publicdelegateint GetTotalDelegate(Staff[] staffs);

In the above declaration, we are told that there is a delegate named GetTotalDelegate, which takes Array of Staff as parameter and returns an integer to the caller. Later, you can create an instance of the delegate type GetTotalDelegate.

Creating a delegate reference

Now look at the below statement:

GetTotalDelegate Salary_Total = new GetTotalDelegate(Total_Salary );

In the above statement we created the instance of delegate reference. What reference? Salary_Total. What is the type of Reference? GetTotalDelegate.As you see, you are actually creating an object of type GetTotalDelegate. Now, go ahead and look at the syntax example once again. Got, the clue? Right. As per the example, the compiler will actually create a class of type GetTotalDelegate and accepts any function name (Takes it as address reference) that takes an array of Staff and returns an integer. Here Total_Salary is the name of the function we are passing in and that function takes an Array of Staff and returns an integer.

Boring? OK. Let me walk you through an example.

The Staff Class

This class is self-explanatory. It has some field members, a constructor to initialize them and a ToString override. Below is the class:

//001: A class for Staff

publicclass Staff

{

//001_1: Member variables

privateint StaffId;

privatestring StaffName;

publicint Salary;

publicint Bonus;

//001_2: Constructor for Staff

public Staff(int id, string name, int Salary, int bonus)

{

StaffId = id;

StaffName = name;

this.Salary = Salary;

Bonus = bonus;

}

//001_3: String representation of staff

publicoverridestring ToString()

{

returnstring.Format("{0} - {1}", StaffName, StaffId);

}

}

The Organization Class

This class has Array of staffs who forms the Organization.

1) First, a delegate is declared. The delegate name is GetTotalDelegate and it takes array of staff as parameter and returns an integer. Below is delegate:

//002_1: Delegate that Calculates and return the Total

publicdelegateint GetTotalDelegate(Staff[] staffs);

2) Next, two member variables are placed in this class. One is Array of staff and other one is for Name of the Organization.

//002_2: Other member variables

privateStaff[] Staffs;

privatestring Org_Name;

3) The constructor will initialize the internal members. Constructor code is given below:

//002_3: Constructor for Organization

publicOrganization(string Org_name, params Staff[] staffs)

{

//002_3.1: Initialize the Staffs Array

Staffs = new Staff[staffs.Length];

for(int i=0; i<staffs.Length; i++)

Staffs[i] = staffs[i];

//002_3.2: Initialize other member variables

Org_Name = Org_name ;

}

4) The Calculate_Total function takes the delegate of type GetTotalDelegate as parameter. Makes a call to the function referred by the delegate and returns the return value of the delegate parameter delegateRef. Note that when we are making a call with delegate the parameter passed-in is Staff array and as return value integer, the function Calculate_Total return an integer. Here, we do not bother what is implemented by the function that came as the parameter in the form of delegate. Below is the Function that receives function as parameter (Delegate) and returns an integer:

//002_4: Function that delegates the work of Calculating Total

publicint Calculate_Total(GetTotalDelegate delegateRef)

{

return delegateRef(Staffs);

}

5) The DisplayStaffs function walks through the Staffs array and prints the staff object. Note, the ToString override is called as the Console.WriteLine tries to represent the Staff in string format. Below is the function:

//002_5: Diaplay all Staffs

publicvoid DisplayStaffs()

{

foreach(Staff staff in Staffs)

Console.WriteLine(staff);

}

Full Organization class is given below:

//002: Oraganization has Staffs for its Operation

publicclass Organization

{

//002_1: Delegate that Calculates and return the Total

publicdelegateint GetTotalDelegate(Staff[] staffs);

//002_2: Other member variables

private Staff[] Staffs;

privatestring Org_Name;

//002_3: Constructor for Organization

public Organization(string Org_name, params Staff[] staffs)

{

//002_3.1: Initialize the Staffs Array

Staffs = new Staff[staffs.Length];

for(int i=0; i<staffs.Length; i++)

Staffs[i] = staffs[i];

//002_3.2: Initialize other member variables

Org_Name = Org_name ;

}

//002_4: Function that delegates the work of Calculating Total

publicint Calculate_Total(GetTotalDelegate delegateRef)

{

return delegateRef(Staffs);

}

//002_5: Diaplay all Staffs

publicvoid DisplayStaffs()

{

foreach(Staff staff in Staffs)

Console.WriteLine(staff);

}

}

The Calculate Utility Class

If a class has all static functions in it we call it a utility class. As all the members of the class are static, the clients do not need to create an instance and instead they can directly access the function by using the class name. This class implements two functions. One function calculates Total salary and the other function Calculated Total Bonus. Note these function signature maps the delegate we declared on the Organization class. That is both the functions receive Staff Array as parameter and return an integer. The Organization class delegate is going to use these functions and you will see that sooner. Below is the Utility Class [Hope no more explanation is required]:

//003: Utility Class for Making Calculation

publicclass Calculate

{

//003_1: Helper function to Calculate Total Salary Expense

publicstaticint Total_Salary(Staff[] Staffs)

{

int sum = 0;

foreach(Staff staff in Staffs)

sum = sum + staff.Salary ;

return sum;

}

//003_2: Helper function to Calculate Total Bonus for All Staffs

publicstaticint Total_Bonus(Staff[] Staffs)

{

int sum = 0;

foreach(Staff staff in Staffs)

sum = sum + staff.Bonus ;

return sum;

}

}

Delegate usage

Let us see how the user of the above classes uses the delegate. First instances of four Staff are created.

//Client 001: Create Staffs

Staff staff1 = new Staff(100, "Mahesh Chand", 100000, 10000);

Staff staff2 = new Staff(101, "Mike Gold", 80000, 120000);

Staff staff3 = new Staff(102, "Sundar Lal", 70000, 25000);

Staff staff4 = new Staff(103, "Praveen", 50000, 27000);

Next, create the Organization for our example by passing in all the staffs created. The Organization class will copy the array and holds it in the class array member variable Staffs.

Next, two delegate instances Salary_Total, Bonus_Total of the same type GetTotalDelegate are created. Note that for the constructor of this delegate, we are passing the function name that matches the delegate by the arguments it receives and type it returns. The compiler by reading the delegate keyword defines a class called GetTotalDelegate. Well, that is behind the scenes of how delegates work. If you are not a beginner need extra explanation, download the attached source code and examine exe file with ildasm. Look at the internal class GetTotalDelegate that is by the way internal for our Organization class.

//Client 003: Create the Delegates of same type pointing to different function

Once the delegates are created, the total expense spent by the Organization is computed by calling the function Calculate_Total of Organization class. This function expects GetTotalDelegate delegate as parameter. GetTotalDelegate is the wrapper class created by the compiler that point to the function in the code segment. Calculate_Total function just makes a call to the function pointed by the wrapper class GetTotalDelegate and returns the Integer. We are making two calls to the Calculate_Total function. First by sending the Wrapper Class GetTotalDelegate (The delegate type) that points to Total_Salary function of utility class and the second time same type of parameter pointing to different function Total_Bonus. Below is the Code:

//Client 004: Now pass these delegates that is pointer to a function wrapped as a class GetTotalDelegate

2)Move to the directory where you extracted the Zip file, which has the Exe.

3)Type ildasm <Name of the Exe>.exe

4)Examine the to see how the statement publicdelegateint GetTotalDelegate(Staff[] staffs);converted by the compiler as internal class of type GetTotalDelegate

Note:The Example source code is created in Visual studio .net 2003 so that all latest versions can also use it. If you open the solution in the latest version just click the yes button for Convert dialog.

Sivaraman Dhamodaran is a System Engineer. He has over 9 years of experience in IT Industries. He has come across Vc++ & MFC Frame Work, Dot.Net technologies. Oracle and SQL Server.He mostly worked on Desktop datab... Read more