Delegates, Events & Lambdas
What Is a Delegate?
Normally, variables hold data — numbers, strings, objects. But what if you could store a method in a variable? That's exactly what a delegate does.
Think of a delegate as a TV remote control. The remote doesn't know which TV it's pointed at — it just knows "when I press the button, something happens." You can point it at different TVs (different methods), and the button press triggers whatever is currently connected.
This is incredibly powerful because it lets you write flexible code. Instead of hard-coding which method to call, you pass the method as a parameter. The calling code decides what happens.
Delegates — Methods as Variables
Action<T> and Func<T,TResult> — Built-in Delegates
Defining your own delegate types gets tedious. C# provides two built-in generic delegates that cover almost every case:
Action<T>— a method that takes parameters but returns nothing (void).Action<string>takes a string, returns void.Func<T, TResult>— a method that takes parameters and returns a value. The last type is always the return type.Func<int, int, int>takes two ints and returns an int.
You'll rarely need to write your own delegate type anymore — Action and Func handle 99% of cases.
Action, Func & Lambda Expressions
Events — The Notification System
An event is like a newsletter subscription. A publisher (like a Button) says "I have a Click event." Any number of subscribers can sign up with +=. When the event fires, ALL subscribers get notified.
Events use delegates under the hood, but they add restrictions: subscribers can only += (subscribe) or -= (unsubscribe). They can't fire the event or replace other subscribers. This keeps things safe.
Events are the backbone of UI programming (button clicks, form submissions) and many design patterns (observer pattern, pub/sub). Under the hood, event systems often use a queue to process notifications in order.