How to work with delegates in C#

Take advantage of delegates to promote flexibility and code reuse in your .NET applications and to implement event-driven programming with ease.

How to work with delegates in C#
Thinkstock

A delegate is a type that references a method that has the same signature as that of the delegate. In other words, delegates are used to pass methods as arguments to other methods. You can take advantage of delegates in C# to implement event handlers and callback methods. A multicast delegate is one that can point to one or more methods that have identical signatures.

Understanding delegates in C#

Delegates in C# are similar to function pointers in C or C++, but delegates are type-safe. That is, delegates are type-safe references that point to one or more methods that have signatures identical to that of the delegate. We’ll see how to use multicast delegates to reference multiple methods later in this article.

You can declare a delegate that stands on its own or that is nested inside a class. You can pass methods as parameters to a delegate to allow the delegate to point to the method. And you can invoke the method by calling the delegate instance.

First you must create a method that the delegate will point to. We’ll use the following method in our example.

 void ShowText(string str)
   {
      Console.WriteLine(str);
   }

Once we have a method, there are three steps in using delegates: declaration, instantiation, and invocation. The signature of a delegate is shown below.

delegate result-type identifier ([parameters])

You can declare a delegate as shown in the following statement. 

public delegate void MyDelegate(string text);

The delegate declared above has the name MyDelegate, has a return type of void, and accepts a string object as an argument. The delegate MyDelegate can point to any method that has an identical signature, i.e., any method that has the same argument list and return type. Note that the signature of our ShowText method is exactly the same as the signature of MyDelegate.

You must instantiate a delegate before you can use it. The statement below shows how you can instantiate the delegate declared above.

MyDelegate d = new MyDelegate(ShowText);

Once you have declared and instantiated the delegate, you can invoke the method using the delegate.

d("Hello World...");

Here, d is the delegate instance. You can also invoke the method that the delegate instance points to using the Invoke() method on the delegate instance.

d.Invoke("Hello World...");

A delegate example in C#

Here is the complete code listing for the MyDelegate example we stepped through above.

using System;
namespace Delegates
{
    public delegate void MyDelegate(string text);
    class Program
    {
        public static void ShowText(string text)
        {
            Console.WriteLine(text);
        }
        static void Main()
        {
            MyDelegate d = new MyDelegate(ShowText);
            d("Hello World...");
            Console.ReadLine();
        }
    }
}

And here is a second example. Let’s say you have a method that accepts two numbers, adds them together, and returns the sum. You can use a delegate to store the return value of the method as shown in the code snippet given below.

int result = d(12, 15);

Here is the complete code listing.

using System;
namespace Delegates
{
    public delegate int MyDelegate(int x, int y);
    class Program
    {
        static int Sum(int x, int y)
        {
            return x + y;
        }
        static void Main()
        {
            MyDelegate d = new MyDelegate(Sum);
            int result = d.Invoke(12, 15);
            Console.WriteLine(result);
            Console.ReadLine();
        }
    }
} 

Multicast delegates in C#

Note that you can assign multiple delegate objects to a delegate instance using the + operator. You can also combine delegate instances using the static method Combine. A delegate that points to multiple delegates is known as a multicast delegate. 

The runtime maintains a list (called an invocation list) to execute multiple methods. When a multicast delegate is called, the delegates in the list are executed in order.

The following code listing shows how you can use the Combine() method to combine multiple delegate instances.

myDelegate d1 = new myDelegate(Method1);
myDelegate d2 = new myDelegate(Method2);
myDelegate multicastDelegate = (myDelegate)Delegate.Combine(d1, d2);
multicastDelegate.Invoke();

Note that delegate instances are immutable. Whenever you combine delegates, or you subtract a delegate instance from the list, a new delegate instance is created to represent the new or updated list of methods to be invoked.

The following code listing illustrates a multicast delegate. Note the use of the += operator to assign the delegate to multiple methods that have identical signatures.

using System;
namespace Delegates
{
    public delegate void MyDelegate();
    class Program
    {
        public static void Method1()
        {
            Console.WriteLine("Inside Method1...");
        }
        public static void Method2()
        {
            Console.WriteLine("Inside Method2...");
        }
        static void Main()
        {
            MyDelegate d = null;
            d += Method1;
            d += Method2;
            d.Invoke();
            Console.ReadLine();
        }
    }
}

Benefits and drawbacks of delegates in C#

Here are a few benefits of delegates to keep in mind:

  • Delegates can be used to invoke static and non-static methods.
  • A delegate can be used to call one or more methods having identical signatures.
  • Delegates can be used to define callback methods and invoke event handlers.
  • Delegates can be combined into multicast delegates that execute a chain of delegates in order.

Here are some of the downsides of using delegates:

  • A delegate will execute more slowly than a conventional method because the runtime needs to resolve the method reference before the delegate call is resolved and the method is called.
  • An exception thrown in a method referenced by a delegate doesn’t show the reason for the error, which makes debugging more difficult.
  • The more delegates you use, the less readable your code becomes.
  • When you use delegates, the JIT compiler and runtime may optimize far less than conventional functions.

Delegates are ideally suited to implementing event-driven programming. A delegate doesn’t need to know the class of the object to which it refers. All a delegate needs to know is the signature of the method to which it would point. Proper usage of delegates can promote reusability in your code and flexibility in your designs. You can refer to Microsoft’s online documentation to learn more about delegates.

Copyright © 2023 IDG Communications, Inc.