Delegate is really special type of class. Yes, it is a class. That is what it is going to be once you compile your code. It is not just a class. It is a class which is derived from MultiCastDelegate base class. Once you compile the code, dotnet framework will convert the delegate to class and also, it will derive that class from a base class called "MultiCastDelegate".
So why do we need this special class? The regular class cannot do the job which a delegate can do.
Look at the below series of scenario.
public class Program
{
static void Main(string[] args)
{
DataProcessor dataProcessor = new DataProcessor();
dataProcessor.Process(new List<int> { 1, 2, 3, 4 });
Console.Read();
}
}
public class DataProcessor
{
public void Process(List<int> dataCollection)
{
for (int i = 0; i < dataCollection.Count; i++ )
{//long running code}
}
}
I have a class "DataProcessor" that has a method "Process". If I pass data to that method, it will process that.
Scenario 1:
Consider a scenario where data collection is very huge and it may take very long time to process. If I do not get any notification regarding which item is processed currently, then I may be sitting idle without knowing what is going on. Right?
So, to get the notification back, may be I can add one method in "Program" class and call that method from DataProcessor and update like below.
public class Program
{
static void Main(string[] args)
{
DataProcessor dataProcessor = new DataProcessor();
dataProcessor.Process(new List<int> { 1, 2, 3, 4 });
Console.Read();
}
public static void DataProcessUpdateHandler(int index)
{
Console.WriteLine("Update received for Item " + index.ToString());
}
}
public class DataProcessor
{
public void Process(List<int> dataCollection)
{
for (int i = 0; i < dataCollection.Count; i++ )
{
//long running code
Program.DataProcessUpdateHandler(i);
}
}
}
Okay, the issue is resolved for the given scenario. Now, lets add a complexity.
Scenario 2:
I have two different collection of data. When I pass one collection, I need to receive the update in one particular method and if I pass the other collection, then I need the status update on the other method.
Yes, it is still very simple. Because I can pass some kind of indicator to inform the DataProcessor class to tell, which update method should be called. Then DataProcessor can call that particular update method like below.
public class Program
{
static void Main(string[] args)
{
dataProcessor = new DataProcessor();
dataProcessor.Process(new List<int> { 1, 2, 3, 4 }, "DataProcessUpdateHandler1");
dataProcessor.Process(new List<int> { 5, 6, 7, 8 }, "DataProcessUpdateHandler2");
Console.Read();
}
public static void DataProcessUpdateHandler1(int index)
{
Console.WriteLine("Update received by DataProcessUpdateHandler1 for Item " + index.ToString());
}
public static void DataProcessUpdateHandler2(int index)
{
Console.WriteLine("Update received by DataProcessUpdateHandler2 for Item " + index.ToString());
}
}
public class DataProcessor
{
public void Process(List<int> dataCollection, string updateHandledBy)
{
for (int i = 0; i < dataCollection.Count; i++ )
{
System.Threading.Thread.Sleep(1000);
if (updateHandledBy == "DataProcessUpdateHandler1")
Program.DataProcessUpdateHandler1(i);
else
Program.DataProcessUpdateHandler2(i);
}
}
}
Perfect, we resolved that issue as well.
Scenario 3:
Now the scenario is, I have hundreds of data list. The DataProcess must update the status to hundred different update handler method based on the data list passed.
Now it is interesting. Isn't it? If we need to do this, then we need to pass the method unique identifies to the "Process" method of the DataProcess class, and I need to write a switch case to handle each update method. I don't think this is a correct approach.
Instead of sending the unique identifier to the "Process" method, it would be really wonderful if we can pass the Update Method itself as the parameter to the Process method and let the Process method call the method whatever. If that is the case then no need to write the switch case, isn't it?
Reason for calling the delegate as Pointer to Function:
Yes that's right. That would really wonderful if possible. The truth is, it is possible and that is the purpose of delegates. Delegates can hold the function itself. Actually, the address of the function. Address of the function is good enough the call the function. That is the reason, we call the delegate as pointer to the function.
Since we know what is the purpose delegate, let see how do we use it to resolve our issue in the last scenario.
Okay, delegate can hold the address of the function. But how to declare the delegate to hold our update method.
This is very simple. If you have a toy with the shape Square, can you put it inside a triangle box? (Please don't say that if the triangle box is big enough to hold that square box) I am trying something to explain that, the shape and size should be same. Like that,
If you want a delegate to hold your Update method, then both Update method and the delegate signatures must match.
So, I am going to copy one of the update method signature.
public static void DataProcessUpdateHandler1(int index);
Now I will convert this method into delegate. First remove the static keyword, because delegate no need to be static.
public void DataProcessUpdateHandler1(int index);
Now add a delegate keyword in the above line.
public delegate void DataProcessUpdateHandler1(int index);
That's it. You have the delegate to hold your update function. If you want, you have rename the Delegate Name. "DataProcessUpdateHandler1" is the delegate Name (Like class name). So, if you want to create variable for this delegate same like a class, you will create delegate instance.
lets rename it now. Usually, the delegate naming convention would be, the action what it does with "Handler" suffix at the end. So, everything is fine in the name except then numeric "1". I will remove that.
public delegate void DataProcessUpdateHandler(int index);
Now use this delegate in our program and call the methods dynamically. Just for an example, instead of having hundred list, I have it with 3 list. I have replaced the string parameter of "Process" method with the parameter of type delegate what we created.
Please continue reading the next answer where I have explained the remains part of this answer.