Delegates are type-safe function pointers that form the foundation for events, callbacks, and most functional patterns in C#. You declare a delegate type with a specific signature, then assign methods or lambdas to instances. The standard library provides built-in delegate types: Action and its generic variants return void, while Func and its generic variants return a value specified by the last type parameter. A multicast delegate holds references to multiple methods and invokes them in order when called, with += and -= adding and removing handlers. The Predicate
Events are a higher-level mechanism built on delegates that implements the publisher-subscriber pattern with proper encapsulation. While a delegate field can be invoked by any code that has access to it, an event restricts external code to subscribing and unsubscribing only, since only the declaring class can raise it. The standard event pattern uses EventHandler or EventHandler
Lambda expressions are anonymous functions written with the => operator, used heavily with LINQ and delegate-typed parameters. They come in two forms: an expression-bodied form (x => x * x) and a statement-bodied form with curly braces and an explicit return. C# 9+ allows static lambdas that cannot capture variables from the enclosing scope, which avoids the closure allocation that captured variables would otherwise create. Local functions are named methods declared inside another method; unlike lambdas, they can be marked static, generic, and ref/in/out, and they emit as real methods rather than delegate instances when not converted. They are ideal for pure, named subroutines inside methods.
For push-based streams, the IObserver