Menu
Coddy logo textTech

Delegates and Events

Part of the Object Oriented Programming section of Coddy's C# journey — lesson 43 of 70.

A delegate is a type that represents a reference to a method. Think of it as a variable that holds a method instead of data. This allows you to pass methods as arguments, store them in collections, and call them dynamically.

You declare a delegate by specifying the method signature it can reference:

public delegate void Notify(string message);

public class Publisher
{
    public void SendAlert(string msg) => Console.WriteLine("Alert: " + msg);
}

// Usage
Notify notifier = new Publisher().SendAlert;
notifier("System started");  // Alert: System started

Events build on delegates to implement the publish-subscribe pattern. A class raises an event, and other classes can subscribe to receive notifications. The event keyword restricts how the delegate can be used - subscribers can only add or remove handlers, not invoke the event directly.

public class Button
{
    public event Action Clicked;
    
    public void Click()
    {
        Clicked?.Invoke();  // Notify all subscribers
    }
}

// Subscribing
Button btn = new Button();
btn.Clicked += () => Console.WriteLine("Button was clicked!");
btn.Click();  // Button was clicked!

The += operator subscribes a handler, while -= unsubscribes. The ?.Invoke() pattern safely calls the event only if there are subscribers. Events are fundamental to GUI applications, game engines, and any system where objects need to react to changes without tight coupling.

challenge icon

Challenge

Easy

Let's build a temperature monitoring system that uses delegates and events to notify subscribers whenever the temperature changes. This is a classic example of the publish-subscribe pattern that events enable so elegantly.

You'll organize your code across two files:

  • TemperatureMonitor.cs: Create a TemperatureMonitor class in the Monitoring namespace that acts as the publisher. Your monitor should:
    • Have a private field to store the current temperature
    • Declare an event using Action<int> called TemperatureChanged that fires whenever the temperature is updated
    • Have a Temperature property (int) where the setter updates the private field and raises the event with the new temperature value
    Remember to use the ?.Invoke() pattern to safely raise the event only when there are subscribers.
  • Program.cs: In your main file, create a TemperatureMonitor and subscribe two different handlers to its TemperatureChanged event:
    • One handler that prints: Alert: Temperature is now {value} degrees
    • Another handler that prints: Logged: {value}
    After subscribing both handlers, set the temperature twice using values from input. Each time you set the temperature, both handlers should respond.

You will receive two inputs:

  • First temperature value (integer)
  • Second temperature value (integer)

For example, if the inputs are 25 and 30, the output should be:

Alert: Temperature is now 25 degrees
Logged: 25
Alert: Temperature is now 30 degrees
Logged: 30

Notice how setting the Temperature property automatically notifies all subscribers - the monitor doesn't need to know anything about who's listening. That's the beauty of the event-driven approach!

Cheat sheet

A delegate is a type that represents a reference to a method, allowing you to pass methods as arguments, store them in collections, and call them dynamically.

Declare a delegate by specifying the method signature:

public delegate void Notify(string message);

public class Publisher
{
    public void SendAlert(string msg) => Console.WriteLine("Alert: " + msg);
}

// Usage
Notify notifier = new Publisher().SendAlert;
notifier("System started");  // Alert: System started

Events implement the publish-subscribe pattern using delegates. The event keyword restricts delegate usage - subscribers can only add or remove handlers, not invoke the event directly.

public class Button
{
    public event Action Clicked;
    
    public void Click()
    {
        Clicked?.Invoke();  // Notify all subscribers
    }
}

// Subscribing
Button btn = new Button();
btn.Clicked += () => Console.WriteLine("Button was clicked!");
btn.Click();  // Button was clicked!

Use += to subscribe a handler and -= to unsubscribe. The ?.Invoke() pattern safely calls the event only if there are subscribers.

Try it yourself

using System;
using Monitoring;

class Program
{
    public static void Main(string[] args)
    {
        // Read input
        int temp1 = Convert.ToInt32(Console.ReadLine());
        int temp2 = Convert.ToInt32(Console.ReadLine());

        // TODO: Create a TemperatureMonitor instance

        // TODO: Subscribe a handler that prints: "Alert: Temperature is now {value} degrees"

        // TODO: Subscribe another handler that prints: "Logged: {value}"

        // TODO: Set the temperature to temp1

        // TODO: Set the temperature to temp2
    }
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming