Delegates are a way to handle methods in a different way than we are used to. They comprise a basic part of the .Net architecture and are important in order to use technologies like lambda expressions.
What is a delegate?
A delegate is a reference type which can be used as a connection between that and the methods it is assigned. Think of it as a reference type for methods. In a few words, we can create the WriteSthDelegate delegate and the WriteSthMethod method. Then we connect the method to the delegate. Now, we can use the delegate the way we would use the method. Consider a delegate something like a pointer to a method.
Let's see an example.
We will use a simple literal object called DelegateOutputLitID to show the output.
Here's our delegate and the method it will use.
delegate void WriteSthDelegate(string outputText);
void WriteSthMethod(string outputText)
{
DelegateOutputLitID.Text += outputText;
}
and this is the way to associate them
protected void Page_Load(object sender, EventArgs e)
{
DelegateOutputLitID.Text = "";
//Attach WriteSthMethod while creating the writeSthDelegateObject delegate
WriteSthDelegate writeSthDelegateObject = new WriteSthDelegate(WriteSthMethod);
writeSthDelegateObject("Hello, I am a delegate");
}
What do we have here? We create an instance of the WriteSthDelegate and connect it to the WriteSthMethod. From now on, using the delegate in the way of writeSthDelegateObject("Hello, I am a delegate") will be equal to calling the method WriteSthMethod("Hello, I am a delegate")
The output will be
Hello, I am a delegate
Using a diagram, this is the line followed in order to get the result.
Keep in mind that both the delegate and the method must have the same return value and the same arguments. In our case the return value is void and there is one argument of string type.
In addition to using the method directly, the connection between the delegate and the method can occur at runtime and we can thus create a much more flexible application.
Handling delegates
We learned how to assign a method to a delegate. Still, a delegate can be assigned more than one method or dismiss some of the ones it is already assigned.
The way to do this is quite simple. You associate the method you want to a new delegate object and then you either add the two delegates or subtract them, much like you would do if you wanted to add or subtract two integers.
delegateObject += newDelegateObject will assign new methods to a delegate.
delegateObject -= newDelegateObject will remove methods from a delegate's assigned list.
In order to combine two (or more) delegates, they must be instances of the same delegate class.
You can also manage that by using the methods directly. For example the previous commands will be the same as
delegateObject += newDelegateMethod
delegateObject -= newDelegateMethod
To create a useful example we will use one more method
void WriteSthElseMethod(string outputText)
{
DelegateOutputLitID.Text += "<br/>Hello, " + outputText;
}
Now, here's the example
protected void Page_Load(object sender, EventArgs e)
{
DelegateOutputLitID.Text = "";
//Attach WriteSthMethod while creating the writeSthDelegateObject delegate
WriteSthDelegate writeSthDelegateObject = new WriteSthDelegate(WriteSthMethod);
writeSthDelegateObject("Hello, I am a delegate");
DelegateOutputLitID.Text += "<hr/>";
//Attach WriteSthElseMethod to the writeSthDelegateObject delegate
writeSthDelegateObject += WriteSthElseMethod;
writeSthDelegateObject("I am a delegate");
DelegateOutputLitID.Text += "<hr/>";
//Remove WriteSthMethod from the writeSthDelegateObject delegate
writeSthDelegateObject -= WriteSthMethod;
writeSthDelegateObject("I am a delegate");
}
The output will be
Hello, I am a delegate
I am a delegate
Hello, I am a delegate
Hello, I am a delegate
All we did, is what we talked about earlier. We created a delegate attached to a method. Then we attached another method to it and combined it so that the first delegate now is connected to both methods. After that we remove the method assigned first.
Delegates contain a few useful methods, for example GetInvocationList() will return a list of the delegates invoked by the current delegate. If we tried out the following piece of code
DelegateOutputLitID.Text += "<br/>There are now " + writeSthDelegateObject.GetInvocationList().Length + " methods attached to the delegate.<br/>";
foreach (Delegate del in writeSthDelegateObject.GetInvocationList())
{
DelegateOutputLitID.Text += del.Method + "<br/>";
}
we would get
There are now 2 methods attached to the delegate.
Void WriteSthMethod(System.String)
Void WriteSthElseMethod(System.String)
The previous examples should probably have given you an idea of how delegates work. Moving forward, we are going to see a few more advanced uses.
Events and delegates
Let's start off by creating two buttons, each of them invoking a method printing a message when clicked. Here's the code.
<asp:Button runat="server" ID="Button1ID" Text="This is button 1" OnClick="Button1Clicked" />
<asp:Button runat="server" ID="Button2ID" Text="This is button 2" OnClick="Button2Clicked" />
protected void Button1Clicked(object sender, EventArgs e)
{
DelegateOutputLitID.Text += " This is button 1.";
}
protected void Button2Clicked(object sender, EventArgs e)
{
DelegateOutputLitID.Text += " This is button 2.";
}
That's most simple. When I press the first button I get " This is button 1.". When I press the second I get " This is button 2.".
What we have here for each button is an event (Click) and a method (Button1Clicked). What we miss is their connection. By writing OnClick="Button1Clicked" we create an event handler, that is the method that will be called by the event. ASP.NET automatically creates the piece of code that says when the Click event of the control with ID Button1ID is raised, the method that will be called will be Button1Clicked.
What is most important is that these event handlers (actually all event handlers) are implemented using delegates. If that is so we could treat these methods like any other method.
So, the following code
void ButtonHandling()
{
DelegateOutputLitID.Text = "";
Button2ID.Click -= Button2Clicked;
Button2ID.Click += Button1Clicked;
}
would remove the Button2Clicked method from the event handler and put Button1Clicked in its place. If we then clicked the second button we would get
This is button 1.
That is the reason that all event handling methods have the same arguments
protected void EventHandlingMethod(object sender, EventArgs e)
Because they are all invoked by a delegate that also needs these arguments.
Why should I use delegates?
We talked about delegates, what they are and what they do. Based on that, you may be able to tell that like most other advanced tools there may not be times where it will be compulsory for you to use delegates, rather than optionally.
You can use delegates when you have created your methods but do not wish to handle them plainly within the code. In that case, using a delegate may end up in a better organized source code.
Delegates can also be used when you are not completely sure what you want to do in future. You simply create the delegate and later on invoke the methods you feel like.
Delegates still, could be the only solution in case you want to use event handlers or other .Net functions that require delegates.
LINQ and Lambda expressions for example can use delegates in order to assign expressions created on the fly. For example
delegate int linqDelegate(int i);
int LinqDelegate(int i)
{
linqDelegate increase = x => x + 1;
//Equal to int increase(int x){return x +1;}
linqDelegate square = x => x * x;
//Equal to int square(int x){return x * x;}
return square(increase(i));
}
If we called this function
LinqDelegate(5);
we would get 36 as a result.
However, we are going to talk about lambda expressions in a future article.
Summary
Delegates can be loosely described as reference types for methods. In that way, calling the delegate is like calling the method invoked. You can invoke more than one method to a delegate, add them and remove them any way that you want. Delegates are used to create event handling and are also used in LINQ and lambda expressions.