CodeGym /Corsi /C# SELF /Iscrizione all'evento e creazione di handler

Iscrizione all'evento e creazione di handler

C# SELF
Livello 52 , Lezione 2
Disponibile

1. Sintassi per iscriversi a un evento

Immagina un'app per la gestione delle attività: quando un'attività è completata scatta un evento, e un handler può, per esempio, inviare una notifica, aggiornare l'interfaccia o scrivere qualcosa nel log. C# rende l'iscrizione agli eventi comoda e sicura: dichiari esplicitamente quale handler risponde a quale evento.

Iscriversi a un evento in C# è quasi come aggiungersi alla lista degli invitati per una festa:

publisher.MyEvent += HandlerMethod;

Qui publisher è l'oggetto che ha dichiarato l'evento MyEvent, e HandlerMethod è il metodo che verrà chiamato quando quell'evento si verifica.

Vediamo un esempio minimale. Supponiamo di avere un'app per contare i click:

public class Clicker
{
    public event Action Clicked;

    public void Click()
    {
        // Qualcosa è stato cliccato!
        Clicked?.Invoke();
    }
}

Ecco il nostro "publisher" dell'evento Clicked. Ora iscriviamo un handler:

Clicker clicker = new Clicker();

void OnClicked()
{
    Console.WriteLine("Il pulsante è stato premuto!");
}

clicker.Clicked += OnClicked;

// Da qualche parte nel codice
clicker.Click();
// → "Il pulsante è stato premuto!"

Come funziona? Abbiamo aggiunto il nostro metodo OnClicked all'evento "click", e verrà eseguito ogni volta che c'è un click.

2. Event handler: quali sono e come dichiararli

Un handler di evento è un metodo che viene chiamato quando l'evento scatta. La sua firma deve corrispondere al tipo del delegato dell'evento. Per esempio, se l'evento è dichiarato come public event Action Clicked;, l'handler deve essere un metodo senza parametri e senza valore di ritorno.

Handler per Action

void OnClicked() 
{
    Console.WriteLine("L'evento è avvenuto (Action)!");
}

Handler per il classico EventHandler

Quando usi l'approccio classico con EventHandler, l'handler accetta due parametri: il sender (object sender) e i dati dell'evento (EventArgs e):

public class Alarm
{
    public event EventHandler AlarmRaised;

    public void RaiseAlarm()
    {
        AlarmRaised?.Invoke(this, EventArgs.Empty);
    }
}

Alarm alarm = new Alarm();

void AlarmHandler(object sender, EventArgs e)
{
    Console.WriteLine("È scattato l'allarme!");
}

alarm.AlarmRaised += AlarmHandler;
alarm.RaiseAlarm();

Metodi anonimi e lambda

C# permette di usare funzioni anonime e lambda direttamente nell'iscrizione:

clicker.Clicked += () => Console.WriteLine("Another click!");

O un po' più complesso, se l'evento ha argomenti:

alarm.AlarmRaised += (sender, e) =>
{
    Console.WriteLine($"Alarm raised by: {sender}");
};

4. Sfumature utili

Iscrizione e cancellazione: dettagli importanti

La vita reale è quando gli invitati alla festa diventano troppi, o qualcuno vuole andare via. Con i delegati è lo stesso: un handler si può aggiungere (iscrivere) e rimuovere (cancellare):

// Iscrizione
publisher.MyEvent += MyHandler;

// Cancellazione (quando l'handler non serve più)
publisher.MyEvent -= MyHandler;

Perché è importante? Se non ti cancelli, soprattutto nelle app grandi, gli handler possono rimanere "attaccati" e impedire al garbage collector di liberare gli oggetti — da qui leak di memoria.

Più handler

A uno stesso evento puoi iscrivere quanti handler vuoi. Verranno chiamati in ordine di aggiunta.

clicker.Clicked += () => Console.WriteLine("Primo handler!");
clicker.Clicked += () => Console.WriteLine("Secondo handler!");

clicker.Click();
// → Primo handler!
// → Secondo handler!

Puoi anche iscrivere e cancellare handler "al volo" — è flessibile e comodo.

Perché è davvero importante: scenari reali

  • UI (Windows Forms, WPF, WinUI, MAUI): click su un pulsante, cambiamento del testo in un campo — sono tutti eventi.
  • FileSystemWatcher: notifica quando nuovi file appaiono in una cartella.
  • Operazioni asincrone: completamento del download di un file, progresso di task.
  • Sistema di plugin: moduli separati si iscrivono agli eventi dell'app principale.

Il modello basato su eventi permette di costruire architetture estensibili: puoi aggiungere nuovi moduli e iscriverti a eventi esistenti senza cambiare il codice base.

Esempi di iscrizione

Firma dell'evento Esempio di iscrizione Esempio di handler
event Action
ev += Handler;
void Handler() { ... }
event Action<int>
ev += (x) => { ... };
void Handler(int x) { ... }
event EventHandler
ev += Handler;
void Handler(object s, EventArgs e) { ... }
event EventHandler<CustomArgs>
ev += Handler;
void Handler(object s, CustomArgs e) { ... }

5. Errori tipici e insidie

Errore n.1: firma dell'handler non corrispondente.
Se l'evento è dichiarato come event Action<int>, e provi a iscriverti con un metodo senza parametri, il compilatore darà errore. Controlla sempre che il metodo corrisponda alla firma richiesta.

Errore n.2: capture di variabili nelle lambda.
Quando ti iscrivi con una lambda può catturare variabili dall'ambiente esterno (vedi il tema "Closure"). Se dopo l'iscrizione la variabile cambia, l'handler vedrà il nuovo valore, e questo può causare comportamenti inattesi.

Errore n.3: iscriversi a un evento di un oggetto non inizializzato.
Se ti iscrivi a un evento prima che l'oggetto che lo contiene sia creato e inizializzato, rischi un NullReferenceException. Prima di iscriverti assicurati che l'oggetto sia pronto.

Errore n.4: iscrizioni multiple dello stesso handler.
Se lo stesso handler è iscritto più volte, verrà chiamato tante volte quante è stato aggiunto. Non è un bug del linguaggio, ma spesso è una sorpresa sgradita.

2
Compito
C# SELF, livello 52, lezione 2
Bloccato
Più sottoscrittori per un evento
Più sottoscrittori per un evento
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION