Lesson 12 / 25
Delegates, Lambdas and Events
Pass behaviour as data with Func, Action, lambdas and events.
Functions as values
A delegate is a type-safe reference to a method. The BCL's generic delegates cover most needs: Func<T1, ..., TResult> returns a value, Action<T1, ...> returns nothing, and Predicate<T> returns a bool. Lambda expressions create delegate instances inline: x => x * 2, (a, b) => a + b. Lambdas can capture variables from the enclosing scope (closures); captured variables are shared, not copied, so changing them later affects the lambda. Lambdas are everywhere: LINQ, callbacks, configuration (options => { ... }), and the static modifier (static x => x * 2) prevents accidental captures. Events build on delegates for the publisher-subscriber pattern: a class declares public event EventHandler<OrderPlacedEventArgs>? OrderPlaced;, outside code can only += and -= handlers, and only the declaring class can raise it. Forgetting to unsubscribe from long-lived publishers is a classic memory leak.
Func, Action and an event
The discount rule is passed in as a function, so callers choose the policy.
Func<decimal, decimal> festiveDiscount = price => price * 0.9m;
Action<string> log = msg => Console.WriteLine($"[{DateTime.Now:T}] {msg}");
decimal Checkout(decimal price, Func<decimal, decimal> discount) => discount(price);
log($"Pay {Checkout(1000m, festiveDiscount)}");
var shop = new Shop();
shop.OrderPlaced += (_, e) => log($"Order {e.OrderId} placed");
shop.Place("o-1001");
public class Shop
{
public event EventHandler<OrderPlacedEventArgs>? OrderPlaced;
public void Place(string id) => OrderPlaced?.Invoke(this, new OrderPlacedEventArgs(id));
}
public record OrderPlacedEventArgs(string OrderId);Leaving your phone number
Subscribing to an event is leaving your number with a shop: "call me when the stock arrives". If you move away and never cancel, the shop keeps your number forever, which in .NET means it keeps your object alive.
Quick check: Which delegate type fits a method that takes a string and returns nothing?
- Action<string>
- Func<string>
- Predicate<string>
- Func<string, bool>
Answer
Action<string> — Action<T> represents methods with parameters and no return value.