Skip to content

Chapter 2 of 7

Functions, Delegates, and Events

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 delegate has the same shape as Func and was historically used by collection filtering methods like List.Find and Array.FindAll, but Func is the preferred form in modern code, especially with LINQ.

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, where TEventArgs derives from System.EventArgs, and the raising class typically exposes a protected virtual method that calls Invoke on the event. This pattern delivers the sender and the event payload to subscribers, which is why EventHandler is preferred over a plain Action for events. Custom callback delegates like Action remain appropriate for non-event scenarios, such as Timer constructors.

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 interface defines OnNext, OnError, and OnCompleted, while IObservable is a source that subscribes observers. Rx.NET (System.Reactive) is the canonical implementation, and exceptions are delivered through OnError as part of the data flow. For one-off async sequences, IAsyncEnumerable consumed with await foreach is usually a more natural fit. The IAsyncDisposable interface is the async counterpart of IDisposable and is used with await using so that async cleanup (flushing buffers, closing network connections) runs to completion.

All chapters
  1. 1Type System and Language Fundamentals
  2. 2Functions, Delegates, and Events
  3. 3Modern C# Language Features
  4. 4LINQ and Data Querying
  5. 5Asynchronous and Parallel Programming
  6. 6Memory, Performance, and Strings
  7. 7Collections, Concurrency, Resources, and Diagnostics

Drill it

Reading is not remembering. These come from the Csharp Programming deck:

Q

What is LINQ in C#?

LINQ (Language Integrated Query) is a set of features that allows you to write query expressions directly in C# to filter, sort, and transform data from collect...

Q

What is the difference between LINQ query syntax and method syntax?

Query syntax resembles SQL:var q = from x in list where x > 5 select x;Method syntax uses extension methods:var q = list.Where(x => x > 5);Both compile to the s...

Q

What does the LINQ Select method do?

Select projects each element of a sequence into a new form (a transformation/map operation).var names = people.Select(p => p.Name);It returns an IEnumerable<...

Q

What is deferred execution in LINQ?

Deferred execution means a LINQ query is not executed when defined, but only when the results are enumerated (e.g., via foreach, ToList(), or Count()). This all...