A delegate in C# is a type-safe function pointer that can reference methods with a particular signature. It allows methods to be passed as parameters, assigned to variables, and invoked dynamically. Delegates are a fundamental part of building flexible, extensible, and event-driven applications in C#.
Think of a delegate as a contract: any method that matches the signature can be used with the delegate.
π§ Delegate Syntax
Declare and use a delegate:
// 1. Declare a delegate
public delegate void GreetDelegate(string name);
// 2. Create methods that match the delegate signature
public class Greeter
{
public void EnglishGreeting(string name)
{
Console.WriteLine($"Hello, {name}!");
}
public void SpanishGreeting(string name)
{
Console.WriteLine($"Β‘Hola, {name}!");
}
}
// 3. Use the delegate
class Program
{
static void Main()
{
Greeter greeter = new Greeter();
GreetDelegate greet = greeter.EnglishGreeting;
greet("Alice"); // Output: Hello, Alice!
greet = greeter.SpanishGreeting;
greet("Alice"); // Output: Β‘Hola, Alice!
}
}
π Why Use Delegates?
Delegates help in:
- Decoupling components (e.g., event publishers and subscribers).
- Passing behavior as parameters (e.g., callback functions).
- Implementing events in custom controls or APIs.
- Encouraging reusable code by separating logic from behavior.
π§° Built-in Delegate Types
C# provides predefined delegates in the System namespace for convenience:
- Action - for methods that return void.
- Func<TResult> - for methods that return a value.
- Predicate<T> - for methods that return a bool.
Action<string> print = Console.WriteLine;
print("Using Action delegate!");
Func<int, int, int> add = (x, y) => x + y;
Console.WriteLine(add(5, 3)); // Output: 8
π What are Multicast Delegates?
A multicast delegate is a delegate that can hold references to more than one method. When invoked, all methods in the invocation list are called in order.
All delegates derived from System.MulticastDelegate support this feature.
π Example of Multicast Delegates
public delegate void Notify(); // No parameters and void return type
class Notifications
{
public void EmailNotification()
{
Console.WriteLine("Email sent.");
}
public void SMSNotification()
{
Console.WriteLine("SMS sent.");
}
public void PushNotification()
{
Console.WriteLine("Push notification sent.");
}
}
class Program
{
static void Main()
{
Notifications notify = new Notifications();
Notify notifyAll = notify.EmailNotification;
notifyAll += notify.SMSNotification;
notifyAll += notify.PushNotification;
notifyAll();
/*
Output:
Email sent.
SMS sent.
Push notification sent.
*/
}
}
β Removing Methods from Multicast Delegates
You can remove methods from the invocation list using the -= operator:
notifyAll -= notify.SMSNotification;
notifyAll();
/*
Output:
Email sent.
Push notification sent.
*/
β οΈ Key Notes and Limitations
- Only the last method's return value is returned if the delegate has a return type.
- All methods are called in the order they were added.
- Exceptions in one method can prevent subsequent methods from running unless handled.
public delegate int Calculation();
public static int A() { Console.WriteLine("A"); return 1; }
public static int B() { Console.WriteLine("B"); return 2; }
public static void Main()
{
Calculation calc = A;
calc += B;
int result = calc(); // Output: A B, Result: 2 (from B)
Console.WriteLine("Result: " + result);
}
π― When to Use Delegates vs Interfaces vs Events?
Use Case |
Best Choice |
Single method behavior injection |
Delegate |
Polymorphism and multiple methods |
Interface |
Notification to subscribers |
Event/Delegate |
π Real-World Use Cases
- Event Handling: Button clicks, UI interactions.
- LINQ methods: Accept delegates like Func<T, bool>.
- Callbacks: For asynchronous or background operations.
- Strategy Pattern: Swap logic at runtime.
π§ͺ Summary
- β
Delegate: A reference to a method with a specific signature.
- β
Multicast Delegate: Chains multiple methods together.
- β
Enables loose coupling, dynamic behavior, and event-driven programming.
- β
Used extensively in .NET event systems and LINQ.
π Final Thoughts
Understanding and mastering delegates is essential for writing clean, maintainable, and extensible C# applications. Whether you're handling events, implementing design patterns, or building libraries, delegates provide the flexibility and type safety you need.