Back
Events and Delegates in C#

Events and Delegates in C#

In C#, delegates and events are fundamental concepts that enable powerful and flexible communication between objects, especially in event-driven programming. They are often used together, with delegates serving as the foundation for events.

Let's break them down:

Delegates in C#

At its core, a delegate in C# is a type-safe function pointer. This means it's a reference type that holds a reference to a method (or multiple methods). Think of it like a variable that can store a method instead of data.

Key characteristics of Delegates:

  • Type-Safe: A delegate has a specific signature (return type and parameters). It can only reference methods that precisely match that signature. This ensures type safety at compile time.
  • Object-Oriented: Delegates are objects themselves. You can pass them as arguments to methods, store them in variables, and return them from methods.
  • Callback Mechanism: Delegates are widely used to implement callback mechanisms. This means one method can delegate a task to another method, and then be notified (via the delegate) when the task is complete or some action occurs.
  • Multicast Delegates: Delegates can point to multiple methods. When a multicast delegate is invoked, all the methods it references are called in sequence. You use the += operator to add methods to a delegate's invocation list and -= to remove them.
  • Foundation for Events: Events are built on top of delegates.

Analogy: Imagine a TV remote control. The remote (delegate) doesn't perform the action itself, but it has buttons (methods) that, when pressed, instruct the TV (target object) to perform an action like "increase volume."

Syntax for declaring a delegate:

public delegate void MyDelegate(string message);

This declares a delegate named MyDelegate that can point to any method that takes a string as a parameter and returns void.

Example of using a delegate:


using System;

// 1. Declare a delegate
public delegate void MessageHandler(string message);

public class Program
{
    // A method that matches the delegate's signature
    public static void PrintToConsole(string msg)
    {
        Console.WriteLine($"Console Output: {msg}");
    }

    public static void PrintToFile(string msg)
    {
        // In a real application, this would write to a file
        Console.WriteLine($"File Output (simulated): {msg}");
    }

    public static void Main(string[] args)
    {
        // 2. Create an instance of the delegate and assign a method
        MessageHandler handler = PrintToConsole;

        // 3. Invoke the delegate
        handler("Hello from the delegate!"); // Calls PrintToConsole

        // Multicast delegate: Add another method
        handler += PrintToFile;

        // Invoke the delegate again (now calls both methods)
        handler("This message goes to both!");

        // Remove a method
        handler -= PrintToConsole;

        // Now only PrintToFile will be called
        handler("Only to file now!");
    }
}
    
---

Events in C#

An event in C# is a special type of delegate that provides a controlled mechanism for one class (the publisher) to notify other classes (the subscribers or listeners) when something of interest occurs. Events are a core part of implementing the Observer design pattern.

Key characteristics of Events:

  • Encapsulation: Events encapsulate the underlying delegate. This means external classes can only subscribe to (+=) and unsubscribe from (-=) the event. They cannot directly invoke the event or clear its invocation list, ensuring better control and preventing unintended behavior.
  • Notification Mechanism: Events are specifically designed for broadcasting notifications. When an event is "raised" or "fired" by the publisher, all registered subscribers are notified and their respective event handler methods are executed.
  • Built upon Delegates: Events rely on delegates. When you declare an event, you're essentially declaring a special kind of delegate that can only be manipulated in a controlled way by external code.
  • Publisher-Subscriber Model: Events facilitate a loose coupling between classes. The publisher doesn't need to know anything about its subscribers, only that it needs to notify them when an event occurs. Subscribers, in turn, don't need to know how the event was raised, only that it happened.
  • Standard Naming Convention: Events in .NET typically use the EventHandler delegate or EventHandler<TEventArgs> for events that pass custom data. Event handler methods usually follow the On<EventName> naming convention (e.g., OnButton_Click).

Analogy: Think of a fire alarm system. The alarm (event) is triggered when smoke is detected (publisher). The fire department, building management, and occupants (subscribers) are all notified when the alarm rings, but they don't directly control when the alarm goes off.

Syntax for declaring an event:

public event MyDelegate MyEvent;

Here, MyDelegate is a previously defined delegate type.

Example of using an event:


using System;

// 1. Define a delegate for the event (can also use built-in EventHandler)
public delegate void TemperatureChangeHandler(object sender, TemperatureEventArgs e);

// Custom EventArgs class to pass data with the event
public class TemperatureEventArgs : EventArgs
{
    public double NewTemperature { get; }
    public TemperatureEventArgs(double newTemperature)
    {
        NewTemperature = newTemperature;
    }
}

// Publisher class: Monitors temperature and raises an event
public class Thermostat
{
    private double _currentTemperature;

    // 2. Declare an event using the delegate
    public event TemperatureChangeHandler TemperatureChanged;

    public double CurrentTemperature
    {
        get { return _currentTemperature; }
        set
        {
            if (_currentTemperature != value)
            {
                _currentTemperature = value;
                // 3. Raise the event when the temperature changes
                OnTemperatureChanged(new TemperatureEventArgs(value));
            }
        }
    }

    // Protected virtual method to raise the event
    protected virtual void OnTemperatureChanged(TemperatureEventArgs e)
    {
        // Check if there are any subscribers before invoking
        TemperatureChanged?.Invoke(this, e);
    }
}

// Subscriber class: Reacts to temperature changes
public class Heater
{
    public void TurnOn(object sender, TemperatureEventArgs e)
    {
        if (e.NewTemperature < 20)
        {
            Console.WriteLine($"Heater: Temperature dropped to {e.NewTemperature}°C. Turning ON.");
        }
    }
}

public class AirConditioner
{
    public void TurnOff(object sender, TemperatureEventArgs e)
    {
        if (e.NewTemperature > 25)
        {
            Console.WriteLine($"AC: Temperature rose to {e.NewTemperature}°C. Turning ON.");
        }
    }
}

public class Program
{
    public static void Main(string[] args)
    {
        Thermostat thermostat = new Thermostat();
        Heater heater = new Heater();
        AirConditioner ac = new AirConditioner();

        // 4. Subscribers register for the event
        thermostat.TemperatureChanged += heater.TurnOn;
        thermostat.TemperatureChanged += ac.TurnOff;

        Console.WriteLine("Initial Temperature: " + thermostat.CurrentTemperature);

        thermostat.CurrentTemperature = 18; // Heater turns on
        thermostat.CurrentTemperature = 28; // AC turns on
        thermostat.CurrentTemperature = 22; // Neither turns on
    }
}
    
---

Key Differences and Relationship:

Feature Delegate Event
Purpose A type-safe function pointer; encapsulates a method. A notification mechanism for one-to-many communication.
Access Can be invoked directly by any code that has a reference to it. Can only be raised (invoked) by the class that declares it. External classes can only subscribe or unsubscribe.
Usage Used for callbacks, passing methods as parameters, and building events. Used for signaling significant occurrences, implementing the Observer pattern, and GUI programming.
Keyword delegate event (applied to a delegate type variable)
Foundation Is a standalone concept. Built on top of delegates.

In summary, delegates are the underlying mechanism that allows you to treat methods as objects and pass them around. Events are a specific and controlled use case of delegates, providing a structured way to implement notification systems and achieve loose coupling in your C# applications.

Comments - Beta - WIP

Leave a Comment