Delegates and Events

Back

Loading concept...

📢 Delegates and Events: Your Code’s Messenger System

The Story of the Busy Restaurant

Imagine you’re running a busy restaurant. You have:

  • A doorbell (delegate) that rings when customers arrive
  • Waiters (event handlers) who respond to the bell
  • A manager who makes sure everyone gets notified

This is exactly how delegates and events work in C#! They help different parts of your code talk to each other without being tightly connected.


🎯 What is a Delegate?

A delegate is like a sticky note with instructions. Instead of calling someone directly, you write down “call this person when X happens” and pass that note around.

Simple Example

Think of it like this:

  • Your mom says: “When the pizza arrives, call me!”
  • The sticky note says: Call Mom()
  • When pizza comes, you look at the note and call mom
// Declare a delegate (the sticky note format)
delegate void NotifyPerson(string message);

// Create a method that matches the format
void CallMom(string message)
{
    Console.WriteLine(quot;Mom: {message}");
}

// Use the delegate
NotifyPerson notify = CallMom;
notify("Pizza is here!");
// Output: Mom: Pizza is here!

Why Use Delegates?

Without Delegates With Delegates
Call methods directly Pass methods like variables
Tight coupling Loose coupling
Hard to change Easy to swap behaviors

🔗 Multicast Delegates: One Note, Many Calls

What if EVERYONE wants to know when pizza arrives? You can stack multiple methods onto one delegate!

The Family Pizza Alert

delegate void PizzaAlert(string message);

void NotifyMom(string msg)
{
    Console.WriteLine(quot;Mom: {msg}");
}

void NotifyDad(string msg)
{
    Console.WriteLine(quot;Dad: {msg}");
}

void NotifyKids(string msg)
{
    Console.WriteLine(quot;Kids: YAY! {msg}");
}

// Stack them all!
PizzaAlert alert = NotifyMom;
alert += NotifyDad;
alert += NotifyKids;

alert("Pizza has arrived!");

Output:

Mom: Pizza has arrived!
Dad: Pizza has arrived!
Kids: YAY! Pizza has arrived!

Key Points About Multicast

  • Use += to add methods
  • Use -= to remove methods
  • They execute in the order you added them
// Remove dad (he's on a diet)
alert -= NotifyDad;

📦 Built-in Delegates: Ready-Made Sticky Notes

C# gives you three super useful delegates so you don’t have to create your own!

1. Action – Does Something, Returns Nothing

Like a worker who completes tasks but doesn’t report back.

// No parameters
Action sayHello = () => Console.WriteLine("Hello!");
sayHello();

// With parameters (up to 16!)
Action<string> greet = (name) =>
    Console.WriteLine(quot;Hi, {name}!");
greet("Alex");

2. Func – Does Something, Returns a Result

Like a calculator that gives you answers.

// Returns int, takes two ints
Func<int, int, int> add = (a, b) => a + b;
int result = add(5, 3);  // result = 8

// Just returns something
Func<string> getName = () => "Charlie";

3. Predicate – Asks Yes or No Questions

Like a security guard checking: “Can this person enter?”

Predicate<int> isAdult = (age) => age >= 18;

Console.WriteLine(isAdult(20)); // True
Console.WriteLine(isAdult(15)); // False

Quick Reference

Delegate Returns Use When
Action Nothing You want to DO something
Func A value You need an ANSWER
Predicate bool You’re ASKING yes/no

🎪 Events: The Safe Broadcast System

An event is like a radio station. Anyone can tune in (subscribe), but only the station owner can broadcast.

The Difference: Delegate vs Event

// DELEGATE: Anyone can invoke it (dangerous!)
public Action OnClick;  // Outsiders can call this!

// EVENT: Only the owner can invoke (safe!)
public event Action OnClick;  // Protected broadcast

Real Example: A Button Click

class Button
{
    // Declare the event
    public event Action OnClick;

    // Only Button can trigger this
    public void Click()
    {
        Console.WriteLine("Button clicked!");
        OnClick?.Invoke();
    }
}

// Using the button
Button myButton = new Button();
myButton.OnClick += () => Console.WriteLine("Do something!");
myButton.Click();

Output:

Button clicked!
Do something!

📬 Event Handlers and EventArgs

For serious events, C# has a standard pattern using EventHandler and EventArgs.

The Standard Pattern

Think of EventArgs as an envelope that carries extra information about what happened.

// Custom EventArgs (the envelope)
class OrderEventArgs : EventArgs
{
    public string ItemName { get; set; }
    public int Quantity { get; set; }
}

class Store
{
    // Standard event pattern
    public event EventHandler<OrderEventArgs> OrderPlaced;

    public void PlaceOrder(string item, int qty)
    {
        Console.WriteLine("Order processing...");

        // Trigger the event with data
        OrderPlaced?.Invoke(this, new OrderEventArgs
        {
            ItemName = item,
            Quantity = qty
        });
    }
}

Subscribing to the Event

Store shop = new Store();

// Subscribe with a handler method
shop.OrderPlaced += (sender, e) =>
{
    Console.WriteLine(quot;Email sent: You ordered " +
                      quot;{e.Quantity} {e.ItemName}(s)");
};

shop.PlaceOrder("Pizza", 2);

Output:

Order processing...
Email sent: You ordered 2 Pizza(s)

Why Use This Pattern?

  1. sender tells you WHO triggered the event
  2. EventArgs tells you WHAT happened
  3. It’s the standard everyone recognizes

⚠️ Event Memory Leaks: The Forgotten Subscription

Here’s a scary story: forgetting to unsubscribe causes memory leaks!

The Problem

class NewsPublisher
{
    public event EventHandler NewsPublished;
}

class NewsReader
{
    public NewsReader(NewsPublisher pub)
    {
        // Subscribe to news
        pub.NewsPublished += OnNewsReceived;
    }

    void OnNewsReceived(object sender, EventArgs e)
    {
        Console.WriteLine("Reading news...");
    }
    // ❌ Never unsubscribed! Memory leak!
}

Even when NewsReader should be garbage collected, the publisher still holds a reference to it through the event subscription!

The Solution: Always Unsubscribe!

class NewsReader : IDisposable
{
    private NewsPublisher _publisher;

    public NewsReader(NewsPublisher pub)
    {
        _publisher = pub;
        _publisher.NewsPublished += OnNewsReceived;
    }

    void OnNewsReceived(object sender, EventArgs e)
    {
        Console.WriteLine("Reading news...");
    }

    // ✅ Clean up when done!
    public void Dispose()
    {
        _publisher.NewsPublished -= OnNewsReceived;
    }
}

// Usage
using (var reader = new NewsReader(publisher))
{
    // ... use the reader
} // Auto-unsubscribes here!

Memory Leak Prevention Checklist

Problem Solution
Forgot to unsubscribe Implement IDisposable
Long-lived publisher Use weak references
Lambda subscribers Store reference to unsubscribe
// ❌ BAD: Can't unsubscribe lambda
button.Click += (s, e) => DoSomething();

// ✅ GOOD: Store the handler
EventHandler handler = (s, e) => DoSomething();
button.Click += handler;
// Later...
button.Click -= handler;

🎨 Visual Summary

graph TD A["Delegate"] --> B["Holds method reference"] B --> C["Can be invoked"] D["Multicast"] --> E["Multiple methods"] E --> F["Called in order"] G["Event"] --> H["Protected delegate"] H --> I["Only owner invokes"] J["EventArgs"] --> K["Carries data"] K --> L["Standard pattern"] M["Memory Leak"] --> N["Forgot unsubscribe"] N --> O["Use IDisposable"]

🏆 Key Takeaways

  1. Delegates = Methods as variables (sticky notes)
  2. Multicast = Stack multiple methods on one delegate
  3. Built-in delegates = Action, Func, Predicate
  4. Events = Safe, protected broadcasts
  5. EventHandler/EventArgs = Standard event pattern
  6. Memory leaks = Always unsubscribe from events!

🎯 Real-World Uses

Scenario What to Use
Button click handlers event EventHandler Click
Callbacks after async Action<Result> onComplete
Filtering collections Predicate<T>
Transforming data Func<T, TResult>
Logging/notifications event EventHandler<LogArgs>

Now you understand how C# components communicate! Events and delegates are the backbone of modern C# applications, from desktop apps to games to web services. 🚀

Loading story...

Story - Premium Content

Please sign in to view this story and start learning.

Upgrade to Premium to unlock full access to all stories.

Stay Tuned!

Story is coming soon.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.