Menu
Coddy logo textTech

Delegados y eventos

Parte de la sección Programación Orientada a Objetos del Journey de C# de Coddy — lección 43 de 70.

Un delegado es un tipo que representa una referencia a un método. Piénselo como una variable que contiene un método en lugar de datos. Esto le permite pasar métodos como argumentos, almacenarlos en colecciones y llamarlos dinámicamente.

Se declara un delegado especificando la firma del método al que puede hacer referencia:

public delegate void Notify(string message);

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

// Uso
Notify notifier = new Publisher().SendAlert;
notifier("System started");  // Alerta: System started

Los eventos se basan en los delegados para implementar el patrón de publicación-suscripción. Una clase lanza un evento y otras clases pueden suscribirse para recibir notificaciones. La palabra clave event restringe cómo se puede utilizar el delegado: los suscriptores solo pueden agregar o eliminar controladores, no invocar el evento directamente.

public class Button
{
    public event Action Clicked;
    
    public void Click()
    {
        Clicked?.Invoke();  // Notificar a todos los suscriptores
    }
}

// Suscripción
Button btn = new Button();
btn.Clicked += () => Console.WriteLine("Button was clicked!");
btn.Click();  // ¡Se hizo clic en el botón!

El operador += suscribe un controlador, mientras que -= cancela la suscripción. El patrón ?.Invoke() llama al evento de forma segura solo si hay suscriptores. Los eventos son fundamentales para las aplicaciones GUI, los motores de juegos y cualquier sistema donde los objetos necesiten reaccionar a los cambios sin un acoplamiento fuerte.

challenge icon

Desafío

Fácil

Vamos a construir un sistema de monitoreo de temperatura que utiliza delegados y eventos para notificar a los suscriptores cada vez que la temperatura cambia. Este es un ejemplo clásico del patrón de publicación-suscripción que los eventos habilitan de manera tan elegante.

Organizarás tu código en dos archivos:

  • TemperatureMonitor.cs: Crea una clase TemperatureMonitor en el espacio de nombres Monitoring que actúe como el publicador. Tu monitor debe:
    • Tener un campo privado para almacenar la temperatura actual
    • Declarar un evento usando Action<int> llamado TemperatureChanged que se active cada vez que se actualice la temperatura
    • Tener una propiedad Temperature (int) donde el setter actualice el campo privado y active el evento con el nuevo valor de temperatura
    Recuerda usar el patrón ?.Invoke() para activar el evento de forma segura solo cuando haya suscriptores.
  • Program.cs: En tu archivo principal, crea un TemperatureMonitor y suscribe dos controladores diferentes a su evento TemperatureChanged:
    • Un controlador que imprima: Alert: Temperature is now {value} degrees
    • Otro controlador que imprima: Logged: {value}
    Después de suscribir ambos controladores, establece la temperatura dos veces usando los valores de la entrada. Cada vez que establezcas la temperatura, ambos controladores deben responder.

Recibirás dos entradas:

  • Primer valor de temperatura (entero)
  • Segundo valor de temperatura (entero)

Por ejemplo, si las entradas son 25 y 30, la salida debería ser:

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

Observa cómo establecer la propiedad Temperature notifica automáticamente a todos los suscriptores; el monitor no necesita saber nada sobre quién está escuchando. ¡Esa es la belleza del enfoque orientado a eventos!

Hoja de referencia

Un delegado es un tipo que representa una referencia a un método, lo que permite pasar métodos como argumentos, almacenarlos en colecciones y llamarlos dinámicamente.

Declare un delegado especificando la firma del método:

public delegate void Notify(string message);

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

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

Los eventos implementan el patrón de publicación-suscripción utilizando delegados. La palabra clave event restringe el uso del delegado: los suscriptores solo pueden agregar o eliminar controladores, no invocar el evento directamente.

public class Button
{
    public event Action Clicked;
    
    public void Click()
    {
        Clicked?.Invoke();  // Notificar a todos los suscriptores
    }
}

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

Use += para suscribir un controlador y -= para cancelar la suscripción. El patrón ?.Invoke() llama al evento de forma segura solo si hay suscriptores.

Pruébalo tú mismo

using System;
using Monitoring;

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

        // TODO: Crear una instancia de TemperatureMonitor

        // TODO: Suscribir un manejador que imprima: "Alert: Temperature is now {value} degrees"

        // TODO: Suscribir otro manejador que imprima: "Logged: {value}"

        // TODO: Establecer la temperatura a temp1

        // TODO: Establecer la temperatura a temp2
    }
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos