Reader Level:
ARTICLE

Delegates: Part I

On November 09, 2010 Articles | C# Programming
How to create a delegate and use it in C#.
  • 2
  • 0
  • 8425
Download Files:
 

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:

 

Organization Org = new Organization("C# Corner", staff1, staff2, staff3, staff4 );

 

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:

 

public delegate int 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

public class Staff

{

            //001_1: Member variables

            private int StaffId;

            private string StaffName;

            public int Salary;

            public int 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

            public override string ToString()

            {

                        return string.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

public delegate int 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

private Staff[] Staffs;

private string Org_Name;

 

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

 

//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 ;

}

 

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

public int 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

public void DisplayStaffs()

{

            foreach(Staff staff in Staffs)

                        Console.WriteLine(staff);

}

 

Full Organization class is given below:

 

//002: Oraganization has Staffs for its Operation

public class Organization

{

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

            public delegate int GetTotalDelegate(Staff[] staffs);

 

            //002_2: Other member variables

            private Staff[] Staffs;

            private string 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

            public int Calculate_Total(GetTotalDelegate delegateRef)

            {

                        return delegateRef(Staffs);

            }

 

            //002_5: Diaplay all Staffs

            public void 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

public class Calculate

{

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

            public static int 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

            public static int 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.

 

//Client 002: Create Organization

Organization Org = new Organization("C# Corner", staff1, staff2, staff3, staff4 );

Org.DisplayStaffs();

 

Next, two delegate instances Salary_TotalBonus_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

Organization.GetTotalDelegate Salary_Total = new Organization.GetTotalDelegate(Calculate.Total_Salary );

Organization.GetTotalDelegate Bonus_Total = new Organization.GetTotalDelegate(Calculate.Total_Bonus );

 

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

//to the Organization class member function.

int Total_Org_Expenses;

Total_Org_Expenses = Org.Calculate_Total(Salary_Total) + Org.Calculate_Total(Bonus_Total);

Console.WriteLine("Total Expense  : " + Total_Org_Expenses );

 

Closing Notes

 

Download the demo and examine the Exe using the ILDASM.

 

For Beginners [How do I]:

1)   Open the console window using Microsoft Visual Studio <Your Version> => Visual Studio Tools => Visual Studio <Your version> Command Prompt.

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 public delegate int 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

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 wor...

  • 35rank
  • 1M readers
  • 2times
COMMENT USING

Trending up