CodeGym /Corsi /C# SELF /Creare eventi usando i delegati (

Creare eventi usando i delegati ( event e delegate)

C# SELF
Livello 52, Lezione 1
Disponibile

1. Introduzione

Quindi, quando parliamo di «evento» (event) nel contesto di C#, ci riferiamo a un meccanismo che permette di notificare in modo sicuro uno o più oggetti che qualcosa è successo. Gli eventi non sono magia: sotto il cofano sono delegati (la keyword delegate) con protezioni aggiuntive contro usi impropri.

Immagina l'iscrizione a un canale YouTube. Il canale (l'oggetto proprietario dell'evento) ha un pulsante "Iscriviti" — qualsiasi spettatore (un altro oggetto) può premerlo ed entrare nella lista degli iscritti (i delegati-handler). Quando l'autore pubblica un nuovo video (solleva l'evento), solo gli iscritti ricevono la notifica, e solo il proprietario del canale decide quando succede. Dettaglio importante: gli spettatori possono iscriversi o cancellarsi, ma non possono inviare la notifica da soli — quel diritto spetta solo al proprietario del canale.

Un po' di sintassi formale


// Dichiarazione di un delegate che definirà la "forma" dell'handler dell'evento
public delegate void SimpleEventHandler();

// Dichiarazione di un evento basato sul delegate
public event SimpleEventHandler SomethingHappened;

È semplice: event è la keyword per dichiarare un evento, e il tipo dell'evento è sempre definito da un delegate.

2. Primo esempio semplice: evento "Pulsante premuto!"

Passo 1. Definiamo il delegate per gli handler dell'evento


// Handler dell'evento: non ritorna nulla e non accetta parametri
public delegate void ButtonClickHandler();

Passo 2. Classe con evento


public class Button
{
    // Evento: ci si può iscrivere e cancellare, ma non è possibile sollevarlo dall'esterno
    public event ButtonClickHandler Click;

    // Metodo che "premere il pulsante"
    public void Press()
    {
        Console.WriteLine("Pulsante premuto!");
        // Chiamata dell'evento: notificare tutti gli iscritti
        Click?.Invoke();
    }
}

Nota: l'evento è dichiarato basandosi sul delegate, e nel metodo Press l'evento viene invocato con ?.Invoke(). Perché? Perché l'evento può essere vuoto (nessuno si è iscritto), quindi Click è null. L'operatore di chiamata sicura garantisce che gli handler vengano eseguiti solo se ci sono iscritti.

Passo 3. Sottoscrizione all'evento ed esecuzione del codice


// Esempio d'uso
public class Program
{
    public static void Main()
    {
        var button = new Button();

        // Aggiungiamo un "listener" (ci iscriviamo all'evento)
        button.Click += OnButtonClicked;
        button.Click += () => Console.WriteLine("Un altro handler!");

        button.Press(); // Simuliamo la pressione del pulsante

        // Possiamo cancellare l'iscrizione all'evento
        button.Click -= OnButtonClicked;
        button.Press();
    }

    // Handler normale dell'evento
    public static void OnButtonClicked()
    {
        Console.WriteLine("Handler: Il pulsante è stato premuto!");
    }
}

Alla prima pressione verranno eseguiti entrambi gli handler, alla seconda solo la lambda.

3. Differenze tra evento e delegate

A un delegate si possono assegnare liberamente valori e persino sostituire completamente la lista degli iscritti — qualcuno potrebbe scrivere qualcosa come button.Click = null e tutte le iscrizioni precedenti verrebbero "cancellate".

Con un evento è diverso — è più strettamente legato all'oggetto. Solo il proprietario della classe in cui l'evento è dichiarato può invocarlo direttamente (per esempio Click() dall'interno della classe). Qualsiasi altro codice può solo iscriversi tramite += o cancellare l'iscrizione tramite -=, ma non può "azzerare" tutto in una volta. Questo protegge l'incapsulamento e impedisce di "rompere" il sistema di sottoscrizioni.

4. Firma: tipi di delegate per eventi, parametri

La convenzione in .NET è che un handler di eventi riceva due parametri — object sender (chi ha sollevato l'evento) e gli argomenti dell'evento (EventArgs). Si raccomanda di usare i delegate EventHandler o EventHandler<TEventArgs>.

Esempio: delegate con parametri


public delegate void ButtonClickHandler(object sender, EventArgs e);

EventArgs è la classe base per passare informazioni aggiuntive. Se servono più dati, creiamo una propria classe derivata.

Applichiamolo al nostro pulsante


// Classe degli argomenti dell'evento
public class ButtonClickEventArgs : EventArgs
{
    public string UserName { get; }

    public ButtonClickEventArgs(string userName)
    {
        UserName = userName;
    }
}

public class Button
{
    public event EventHandler<ButtonClickEventArgs> Click;

    public void Press(string userName)
    {
        Console.WriteLine("Pulsante premuto!");
        Click?.Invoke(this, new ButtonClickEventArgs(userName));
    }
}

public static void Main()
{
    var button = new Button();
    button.Click += OnButtonClicked;

    button.Press("Vasiliy");
}

public static void OnButtonClicked(object sender, ButtonClickEventArgs e)
{
    Console.WriteLine($"L'utente {e.UserName} ha premuto il pulsante!");
}

5. Schema visivo: come funziona un evento


+-------------+
| Utente      |
+-------------+
      |
      v
+--------------+
|  Button.Press|
+--------------+
      |
      v
+-----------------+         +------------------------+
|  Chiamata Click?|----->---|   Iscritto 1           |
+-----------------+         +------------------------+
      |                     |   Eseguire handler     |
      v                     +------------------------+
+-----------------+         +------------------------+
|   Se c'è un     |----->---|   Iscritto 2           |
|   iscritto      |         +------------------------+
      :                     |   Eseguire handler     |
      v                     +------------------------+

— Button.Press invoca l'evento; gli handler degli iscritti vengono eseguiti in ordine.

6. Sfumature utili

Forma raccomandata per gli eventi in .NET

Usa EventHandler e EventHandler<TEventArgs> per mantenere compatibilità con librerie e strumenti. Questo approccio rende più facile evolvere gli eventi: aggiungi nuove proprietà ai tuoi EventArgs senza rompere gli iscritti.

Documentazione: EventHandler, event.

Eventi vs delegate

Se devi collegare un componente a un metodo specifico — un delegate può bastare (delegate). Se invece vuoi permettere a diverse parti del programma di iscriversi e cancellarsi in qualsiasi momento — usa un evento (event).

7. Errori tipici e situazioni imbarazzanti quando crei eventi

Errore №1: invocare l'evento senza controllare null. Se non ci sono iscritti, un tentativo diretto di invocare l'evento causerà una NullReferenceException. Usa la chiamata sicura:


Click?.Invoke(...);

Errore №2: tentare di invocare l'evento dall'esterno della classe. Un evento può essere sollevato (invocato) solo all'interno della classe dove è dichiarato. Da un'altra classe il compilatore segnalerà un errore — questo protegge l'incapsulamento.

Errore №3: iscrizione multipla dello stesso handler. Se lo stesso handler è iscritto più volte, verrà chiamato tante volte. Questa è una caratteristica del meccanismo di sottoscrizione. Fai attenzione ai duplicati con += e a rimuovere correttamente con -=.

2
Compito
C# SELF, livello 52, lezione 1
Bloccato
Implementazione di un semplice evento "Bottone premuto"
Implementazione di un semplice evento "Bottone premuto"
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION