A delegate is a type-safe function pointer — it holds a reference to a method and allows you to pass methods as arguments.
// Declare a delegate type
public delegate int MathOperation(int a, int b);
// Methods that match the signature
static int Add(int a, int b) => a + b;
static int Multiply(int a, int b) => a * b;
// Use the delegate
MathOperation op = Add;
Console.WriteLine(op(3, 4)); // 7
op = Multiply;
Console.WriteLine(op(3, 4)); // 12
public delegate void Notify(string message);
static void Email(string msg) => Console.WriteLine($"Email: {msg}");
static void SMS(string msg) => Console.WriteLine($"SMS: {msg}");
Notify notify = Email;
notify += SMS; // both methods called
notify("Server is down!");
// Email: Server is down!
// SMS: Server is down!
// Func — returns a value: Func<params..., returnType>
Func<int, int, int> add = (a, b) => a + b;
Func<string, string> upper = s => s.ToUpper();
Func<int, bool> isEven = n => n % 2 == 0;
// Action — returns void: Action<params...>
Action<string> print = msg => Console.WriteLine(msg);
Action greet = () => Console.WriteLine("Hello!");
Console.WriteLine(add(3, 4)); // 7
Console.WriteLine(upper("hello")); // HELLO
print("World");
// Special case: Func<T, bool>
Predicate<int> isPositive = n => n > 0;
var numbers = new List<int> { -3, -1, 0, 2, 5 };
var positive = numbers.FindAll(isPositive); // [2, 5]