Working with Delegates: Part I


Working with Delegates

 

We all are well aware about functions. In conventional way, we create object and we call object.method(). We know that they perform some given task and returns results based on the parameters we passed to them. Now please look at the following cases.

 

Why do we need delegates?

 

Case 1:

 

You have a business class where you have some functions F1, F2, F3 (with similar signatures). You have completed the project and you are using function F2 in so many places, around 100 locations. Now there is a change request that you are supposed to use F3 and not F2. Now the only way you have is, to go back to those 100 places and find/replace your F2 with F3.

 

Wouldn't it be awesome if you have somebody to represent the function F2, so that you can just tell him not to execute F2 and instead he has to make use of function F3?  In such case, the change has to be made only in ONE location - to the representative alone. Yes, delegates are your functional representatives. They are nothing but functional pointers. They are nothing but command objects that will work based on your commands. Delegate represents strongly typed functions.

 

Case 2:

 

What if you want to execute those three functions one by one? What if you want your representative to take care of more than one method? Multicast delegates will give you a hand. We will discuss this later.

 

Case 3:

 

Assume your function F1 takes long time to execute. You are forced to wait until it gets completed, before you are allowed to proceed with function F2. You can cross this hurdle by making use of asynchronous call with the help of delegates.

 

Case 4:

 

You are in a situation where you wanted to pass a method as a parameter to another method. There you have delegates that can be treated as a data type as others do.

 

Case 5:

 

Assume you are in a situation where you want the parameters of your methods to be treated in different logics. The logic that needs to be used has to be passed through your front layer. To make it simple, you have to pass two numbers to a function and the logic of treatment, i.e. whether it has to be added or subtracted or multiplied; has to be decided by the front layer. Here delegates are most welcome.

 

Method and Target

 

Every delegate has its own method and target properties. The prime idea of this is nothing but to invoke the method in target object.

 

Simple Approach

 

Assume there are two functions for a class say, DelegateManager (dm).

 

  • public void SayHello(string input)
  • public void Display (string display)

Note they both take string parameter and both of them are void method. In other words, they both have similar signature. You can represent this by a delegate.

 

public delegate string MyDelegate(string str);

 

Instances of this delegate can represent any of these two methods.

 

// using same delegate to execute both the functions

MyDelegate d1 = new MyDelegate(dm.SayHello);

MyDelegate d2 = new MyDelegate(dm.Display);

 

Note down there is no parenthesis while declaring the functions. We are passing functional pointer to the delegate. You can just invoke the delegate by,

 

d1("abc");

d2("cde");

 

Every instance of the delegate will represent the given method. MyDelegate cannot represent any other class, which does not match the type.

 

As we discussed in case 4, you can also treat methods (i.e. delegates) as data types. You can pass them anywhere you wish to.

 

Inversion of Controls – IOC

 

Let us look at a class our business control where I need to add 100 and 25. I am going to make use of the Add method of a Calculator class.

 

Business Control:

 

public delegate int CalculatorHandler(int x, int y);

public class business

{

    public int CallMe(CalculatorHandler ch)

    {

        // Note i am making use of Calculator class

        // without its reference

        int result = ch(100,25);

        return result;

    }

}

 

Front layer:

 

private void button2_Click(object sender, EventArgs e)

{

    Calculator c = new Calculator();

    BusinessControl.business bc = new BusinessControl.business();

    BusinessControl.CalculatorHandler ch = new BusinessControl.CalculatorHandler(c.Add);

    // IOC technique

    int Result = bc.CallMe(ch);

    MessageBox.Show(Result.ToString());

}

 

This technique is called IOC (Inversion of Control), i.e. the control is injected at runtime. We are using the 'bc' business control to which the delegate has to be passed.

 

You can toggle between methods of similar signatures by changing the function pointer. If you want to work with Divide method, just replace c.Add with c.Divide, that’s it.

 

Usage in Real time

 

Let us assume your business class needs to call n number of functions f1, f2, f3 & f4 in a specific order.

 

Assume there is a change request, that you want to insert a new function between f2 and f3 and f4 to be replaced with f5. All you have in front is to do mere Replace.

 

Instead if I had followed IOC, the business class is not related to any of the functions, in turn it executes delegates.

 

A mediator will create instance of business rules and then pass it on to business logic. If you run business control with specific business rule, the best way is to use mediator pattern.

 

We will discuss about Multicast delegates, Synchronous and Asynchronous communication, Callbacks with examples in next part. I will also try to upload some sample code as well.

 

Please mark your comments and suggestions.


Similar Articles