There is a famous quote by Jim Henson: “If you can’t beat them. Join them”.
It’s possible to write code for years without deliberately using delegates. I say “deliberately” because we may have used them without realizing it. Knowing what these types represent makes reading code easier. Knowing how to use them adds some useful tools to our developer toolbox. So instead of ignoring them, why not learn them. In this post, I will show you how you can get started with delegates and their use cases, which will encourage you to use them more in your code.
There are multiple definitions of delegates and one might make more sense over the other. Let’s see a few of those:
- A delegate is a type that represents a method with a specific signature and return type.
- A delegate is a pointer or a reference to a method.
- A delegate is a pipeline.
Still cryptic? Here are a few examples:
A delegate representing a method that adds two numbers and returns a result:
delegate int AddNumbers(int value1, int value2);
A delegate representing a method that logs an exception and doesn't return anything:
delegate void LogException(Exception ex);
A delegate representing a function that converts some generic type to a string:
delegate string FormatAsString(T input);
Notice, The declaration of a delegate looks exactly like the declaration of a method, except with the keyword
delegate in front of it.
Just like classes and interfaces, we can declare delegates outside of classes or nested within classes. We can mark them private, public, or internal.
With delegates, we can pass our methods (functions) around like values.
Delegates In Action
Let’s see a working example of delegates. Here I started with defining a delegate MathCalculation with accepts two floats and return a double. Then I created two variables of this type and assign methods to those variables. And finally, we invoke/call them and display the results:
So, in the delegate world, instead of calling the methods directly, we have now an indirection, we are invoking the methods using delegates instead. Having this capability offers a lot of flexibility which we will learn more about as we move forward. A common use case is to implement reactions to specific events and call-back methods.
Let’s see another example of delegates. The code is very similar to what we have already seen in the Calculator example:
Define a delegate:
Here is the ServerInfo class, we will use its method to assign to delegate types. Notice the methods signature match the delegate defined earlier:
And here is code block which is using delegates:
output of this is shown below:
Events Relationship With Delegates
I’ve written few posts about .NET Events and you can check those if you need more information. Here I will just point out their relationship with delegates.
- Events are associated with delegates.
- A standard .NET Event accepts Sender and EventArgs.
- The signature of EventHandler matches to delegate.
- EventHandler<T> provides a simple way to create a custom delegate for an event.
Let’s see another example of delegates:
I created classes to generate a static list of employees as shown below:
Here is the main method using these classes:
If we run the code it will display information as shown below:
Nothing special so far, the typical way of writing code.
Let’s imagine, that inside the loop, we don’t want to use Console.WriteLine directly or in other words, we dont want to hardcode the part which deals with printing. Instead, we want this logic to comes from somewhere else. This part can be sent as a parameter from outside. Sounds familiar? yes, we can use delegate which as we saw before is a pointer to a function.
I created a delegate called Print:
Then I defined the function which has the same signature as a delegate:
Now, we can use it in the main method as shown below:
And you might have already guessed it, running this code produces the same output, but we have now delegate indirection in-place:
Now, update our code to wireup a different print delegate to display employee info:
I create a new method in PrintingUtils class which has the same signature as the delegate, just the implementation is different:
Here is the updated delegate wiring and usage code:
The output now shows the Id as well along with Name:
Notice that with the use of delegates our code is already beginning to be loosely coupled and you can take this ability to next level, implement business rules as delegates, and pass them around, etc. You can pass functions to other functions as well. There are a lot of places you can use delegates.
In this post, I tried to describe delegates and how to use those in your code. We also saw some information about their relationship with Events. You can read about Events in this post. The code for the demos is available on this link. Till next time, Happy Coding.