Deep Dive Into C# Delegates & Multicast Delegates
Lesson 16 โข Advanced Track
What You'll Learn
- Understand delegates as type-safe function pointers in C#
- Create custom delegate types and assign methods to them
- Use multicast delegates to invoke multiple methods from a single call
- Add and remove targets from a delegate's invocation list
- Replace custom delegates with Func<T>, Action<T>, and Predicate<T>
- Compose function pipelines using delegate chaining
๐ก Real-World Analogy
A delegate is like a job description. It specifies "I need someone who can take two integers and return an integer" โ it doesn't care who fills the role. You can assign Alice (Add), Bob (Multiply), or Charlie (Power) to the same position. A multicast delegate is like a group email โ one send triggers delivery to everyone on the list. You can add and remove recipients dynamically.
๐ Delegate Types Quick Reference
| Type | Signature | Use When |
|---|---|---|
| Custom delegate | delegate int Op(int a, int b); | Rare โ use for domain-specific naming |
| Func<T, TResult> | Func<int, int, int> | Method with return value (up to 16 params) |
| Action<T> | Action<string> | Void method (up to 16 params) |
| Predicate<T> | Predicate<int> | Returns bool โ filtering/matching |
1. Delegate Fundamentals
A delegate is a type that represents a method signature. You declare a delegate type, then assign any method that matches the signature. Delegates enable the strategy pattern โ passing different algorithms to the same function.
Delegate Basics & Strategy Pattern
Create custom delegates and pass methods as parameters.
using System;
// 1. Declare a delegate type (a "function signature contract")
delegate int MathOperation(int a, int b);
class Program
{
// Methods that match the delegate signature
static int Add(int a, int b) => a + b;
static int Multiply(int a, int b) => a * b;
static int Power(int a, int b) => (int)Math.Pow(a, b);
static void Main()
{
// Assign a method to a delegate variable
MathOperation op = Add;
Console.WriteLine($"Add(5, 3) = {op(5, 3)}"
...2. Multicast Delegates
All delegates in C# are multicast โ they can hold references to multiple methods. Use += to add targets and -= to remove them. When invoked, all methods fire in order. Use GetInvocationList() to inspect the chain.
Multicast Delegates
Chain multiple methods into one delegate and manage the invocation list.
using System;
delegate void Logger(string message);
class Program
{
static void ConsoleLog(string msg)
=> Console.WriteLine($"[CONSOLE] {msg}");
static void FileLog(string msg)
=> Console.WriteLine($"[FILE] {msg}"); // Simulated
static void AlertLog(string msg)
=> Console.WriteLine($"[ALERT!] โ ๏ธ {msg}");
static void Main()
{
// Multicast: combine multiple methods into one delegate
Logger logger = ConsoleLog;
logger +=
...3. Func, Action & Predicate
The .NET framework provides built-in generic delegates so you rarely need custom ones. Func<T, TResult> returns a value, Action<T> returns void, and Predicate<T> returns bool. Combine them with lambdas for clean, functional-style code.
Func, Action & Predicate
Use built-in delegates with lambdas and compose function pipelines.
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
// Func<T, TResult> โ has a return value
Func<int, int, int> add = (a, b) => a + b;
Func<string, string> shout = s => s.ToUpper() + "!!!";
Func<int, bool> isEven = n => n % 2 == 0;
Console.WriteLine($"add(3, 7) = {add(3, 7)}");
Console.WriteLine($"shout("hello") = {shout("hello")}");
Console.WriteLine($"isEven(4) = {isEven(4)}");
// Actio
...Pro Tips
- ๐ก Prefer Func/Action over custom delegates: They're universally understood and reduce type proliferation.
- ๐ก Multicast return values: Only the last method's return value is captured. Use multicast delegates primarily with
Action(void methods). - ๐ก Thread safety: Cache a delegate reference locally before invoking:
var handler = MyDelegate; handler?.Invoke(); - ๐ก Lambdas are anonymous delegates:
(x, y) => x + yis shorthand for creating a delegate instance.
Common Mistakes
- Null delegate invocation: Calling an unassigned delegate throws
NullReferenceException. Always usemyDelegate?.Invoke()or null-check first. - Expecting multicast return values: If 3 methods return different ints, only the last one's result is returned. Don't rely on return values from multicast delegates.
- Memory leaks with delegates: Delegates hold references to their target objects. Long-lived delegates pointing to short-lived objects prevent garbage collection.
- Removing lambdas from multicast:
logger -= (msg) => Console.WriteLine(msg)doesn't work โ each lambda is a new instance. Store the lambda in a variable first.
๐ Lesson Complete
- โ Delegates are type-safe function pointers โ they define a method signature contract
- โ
Custom delegates:
delegate int Op(int a, int b);โ rarely needed - โ
Multicast delegates chain multiple methods with
+=and-= - โ
Func<T>returns a value,Action<T>returns void,Predicate<T>returns bool - โ
Lambdas are anonymous delegate instances:
(a, b) => a + b - โ
Always null-check delegates before invoking with
?.Invoke() - โ Next lesson: Events โ advanced patterns and custom EventArgs
Sign up for free to track which lessons you've completed and get learning reminders.