One of the common questions an interviewer may ask you is “What are delegates in C#? How do we use it? What is a real-life scenario?” I used to get confused when I was asked to explain delegates. The only one-liner explanation I had was, “It is used as a reference to a specific method”.
Since I now know exactly what a delegate is, let me explain it to you with a real-life example.
When we talk about delegates, it seems like a method call, but it is actually a class that refers to a method. Saying this much doesn't explain the exact definition of delegates.
It is a keyword (class) of reference type and it is used to encapsulate named or anonymous methods. The advantages of using delegates are:
- Method can be passed as a parameter
- They are type safe
- They are useful in chaining
- They are used to define callbacks
- Event handling
- Covariance & contravariance
- Anonymous methods referencing
We will be talking about each point with an example. First of all let us understand the syntax of declaring a delegate in C#.
access-specifier delegate returntype identifier ([parameters]);
Where:
- access: specifier can be public/private/protected delegate; it is a keyword
- returntype: that matches the return type of the method it is referencing
- identifier: name of delegate
- parameters: matching parameter of a method
When we use as an example a Magazine, it mainly consists of various types of articles written by various authors along with the author's name. Let's continue with this example. Here, we will create a Magazine class that has multiple sections like "Political Talk", "Gadget Talk" and so on.
- public delegate string GetArticle(string articleName);
Passing method as a parameter
Suppose I want to fetch an article related to a gadget written by Paul. I am creating a delegate over here.
- namespace DelegateEx
- {
- public delegate string GetArticle(string articleName);
- public class Magazine
- {
-
- public string strData = "";
- public string PoliticsTalk(string details)
- {
- strData = strData + "Politics Talk By " + details + "\n";
- return strData;
- }
-
- public string GadgetTalk(string details)
- {
- strData = strData + "Gadget Talk By " + details + "\n";
- return strData;
- }
-
- }
-
-
- }
-
-
- static void Main(string[] args)
- {
- Magazine obj = new Magazine();
- GetArticle article = null;
-
-
- article = new GetArticle(obj.GadgetTalk);
- string result = article("Paul");
- Console.WriteLine(result);
- }
In the preceding code, I have called a method GadgetTalk() using the delegate GetArticle. When we create an object of delegate type, its constructor takes as the parameter a method name to be called. This way, we are hiding the actual method name from the user.
Type Safe
The method name passed as a parameter should match the delegate signature. The signature check is done at compile time. So delegates are called type safe. Now, how does the compiler know that it should call GadgetTalk? Actually, the compiler does not know which method to call. It is unaware of the method call. At runtime, the article object is instantiated with the reference type object in the heap. This object calls the appropriate method by the information received from the delegate. The major reason for using the delegate is that the method call is identified at runtime instead at compile time.
Multicast delegate (Chaining)
Multicasting means pointing to more than one function at a time. Here, we make use of the "+" operator to create an invocation list of methods to be referenced using a single delegate. This is helpful in chaining method calls. In an example given below, I want to fetch all articles written by the author Paul.
- static void Main(string[] args)
- {
- Magazine obj = new Magazine();
- GetArticle article = null;
-
-
- article = new GetArticle(obj.GadgetTalk);
- article += new GetArticle(obj.PoliticsTalk);
- article("Paul");
- Console.WriteLine(obj.strData);
- }
The preceding example demonstrates a single delegate that is referencing two methods, GadgetTalk() and PoliticsTalk(). A single delegate object is used for calling both of the methods. The "+" operator adds more than one reference to the method. Similarly, to remove a reference from the delegate, the negation sign can be used as in the following:
article -= new GetArticle(obj.PoliticsTalk);
The Multicast delegate thus helps in chaining the methods.
Callback
A callback is the most important concept of a delegate. Once you are done with calling your method, you can notify another method to execute. The following code snippet shows how a callback works using a delegate. Here I would like to display the published date along with the Gadget talk article written by the author Paul. For this, I have passed a delegate as a parameter to the public method. In the Main class I will be deciding which method to register and which to call. This is one more advantage of using delegates.
- public void GetArticleDetails(string writer, GetArticle articleObj)
- {
- Console.WriteLine("Publish Date:" + DateTime.Now.ToShortDateString());
- Console.WriteLine(articleObj(writer));
- }
-
- static void Main(string[] args)
- {
- Magazine obj = new Magazine();
- GetArticle article = null;
-
-
-
- article = new GetArticle(obj.GadgetTalk);
- obj.GetArticleDetails("Paul", article);
-
- }
Conclusion
A delegate is the most powerful concept in C#. There are other advantages like Event handling. Covariance & Contravariance and Anonymous methods referencing will be explained in my next article. So stay tuned. Please share your comments, whether it's good or bad. Your comments will be valuable to me to improve. For code you can download the sample project that I have attached to this article.