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
- Type Safety: Delegates enforce that the signature of the target method matches the delegate definition.
- Multicast Capability: A delegate can reference multiple methods and invoke them in sequence.
- 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:
- Action: Represents a method that takes input parameters but does not return a value.
Action<string> action = (message) => Console.WriteLine(message);
action("Hello, Action!");
- 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
- 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
- Encapsulation: Encapsulate method references into a single entity.
- Flexibility: Enable dynamic method invocation.
- Reusability: Simplify code by reusing delegates across different parts of an application.
- 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.