Delegates in C# are type-safe function pointers that allow methods to be passed as parameters, stored as variables, or dynamically invoked at runtime.

They are a cornerstone of event-driven programming and play a key role in defining events, callbacks, and lambda expressions.


Key Features of Delegates

  1. Type Safety: Delegates enforce that the signature of the target method matches the delegate definition.
  2. Multicast Capability: A delegate can reference multiple methods and invoke them in sequence.
  3. Encapsulation: Delegates encapsulate methods, making them easier to work with dynamically.

Defining and Using Delegates

1. Declare a Delegate

A delegate is defined using the delegate keyword.

public delegate void MyDelegate(string message);

This declaration specifies that MyDelegate can point to any method with:

  • A void return type
  • A single string parameter

2. Assign Methods to a Delegate

public class Program
{
    public static void ShowMessage(string message)
    {
        Console.WriteLine(message);
    }

    public static void Main()
    {
        MyDelegate del = ShowMessage; // Assigning a method to the delegate
        del("Hello, Delegates!");    // Invoking the delegate
    }
}

Output:

Hello, Delegates!

Multicast Delegates

Delegates can point to multiple methods. This is called a multicast delegate.

Example:

public class Program
{
    public static void ShowMessage(string message)
    {
        Console.WriteLine($"Message: {message}");
    }

    public static void ShowUppercaseMessage(string message)
    {
        Console.WriteLine($"Uppercase Message: {message.ToUpper()}");
    }

    public static void Main()
    {
        MyDelegate del = ShowMessage;
        del += ShowUppercaseMessage; // Add another method

        del("Hello, Multicast Delegates!"); // Both methods are invoked
    }
}

Output:

Message: Hello, Multicast Delegates!
Uppercase Message: HELLO, MULTICAST DELEGATES!

Using Delegates as Parameters

Delegates are commonly used to pass methods as parameters, enabling dynamic behavior.

Example:

public class Program
{
    public delegate int MathOperation(int x, int y);

    public static int Add(int x, int y)
    {
        return x + y;
    }

    public static int Multiply(int x, int y)
    {
        return x * y;
    }

    public static void PerformOperation(int a, int b, MathOperation operation)
    {
        Console.WriteLine($"Result: {operation(a, b)}");
    }

    public static void Main()
    {
        PerformOperation(5, 3, Add);       // Pass Add method
        PerformOperation(5, 3, Multiply);  // Pass Multiply method
    }
}

Output:

Result: 8
Result: 15

Anonymous Methods with Delegates

You can define inline methods using anonymous methods.

Example:

MyDelegate del = delegate (string message)
{
    Console.WriteLine($"Anonymous: {message}");
};

del("Hello from Anonymous Method!");

Lambda Expressions with Delegates

Lambda expressions provide a concise way to define methods for delegates.

Example:

MyDelegate del = (message) => Console.WriteLine($"Lambda: {message}");

del("Hello from Lambda!");

Built-In Delegates

C# provides several built-in generic delegates:

  1. Action: Represents a method that takes input parameters but does not return a value.
Action<string> action = (message) => Console.WriteLine(message); 
action("Hello, Action!");
  1. Func: Represents a method that takes input parameters and returns a value.
Func<int, int, int> func = (x, y) => x + y; 
Console.WriteLine(func(5, 3)); 
// Output: 8
  1. Predicate: Represents a method that takes an input parameter and returns a bool.
Predicate<int> isPositive = (x) => x > 0;
Console.WriteLine(isPositive(5));
// Output: True

Advantages of Delegates

  1. Encapsulation: Encapsulate method references into a single entity.
  2. Flexibility: Enable dynamic method invocation.
  3. Reusability: Simplify code by reusing delegates across different parts of an application.
  4. Event Handling: Form the foundation of event handling in .NET.

When to Use Delegates

  • Event Handling: Link UI or system events to custom logic.
  • Callback Methods: Notify one component when another component completes an operation.
  • Dynamic Invocation: Allow users to supply custom behavior at runtime.

By davs