C# – Gestione degli eventi

1. Introduzione

I delegate vengono usati diffusamente per la gestione degli eventi, cioè quando voglio fare in modo che una classe fornisca delle notifiche ai suoi utilizzatori.

L’azione può essere causata dall’utente, ad esempio il clic su un pulsante oppure può essere generata da un altro programma logico, ad esempio modificare le proprietà di un valore.

La classe che invia (o genera) l’evento è chiamata event sender e le classi che ricevono (o gestiscono) l’evento sono chiamate subscribers.

Il mittente dell’evento non sa quale oggetto o metodo riceverà (dovrà gestire) gli eventi generati.

1.1 Come usare gli eventi

Ora, conosciamo i delegate come dei puntatori a funzione identificati univocamente dala loro firma.

Pensiamo allo scopo degli eventi: vogliamo che un particolare codice venga eseguito quando accade qualcosa da qualche parte nel mio sistema.

Per fare questo, creiamo dei metodi specifici per il codice che vogliamo che venga eseguito.

Il collante tra l’evento e il metodo sono i delegati: l’evento deve internamente memorizzare una lista di puntatori a funzioni da eseguire quando tale evento viene lanciato (aggiunti tramite il comando +=).

Ovviamente se vogliamo chiamare un metodo, dobbiamo sapere quali parametri passare a quest’ultimo!
Consideriamo i delegate quindi come dei “contract” tra l’evento e i metodi che vengono chiamati.

Quando dichiaro un evento con la parola chiave event, devo indicare come tipo un delegate, quindi la firma del metodo che deve essere chiamato al lancio dell’evento.

//Definisco una firma che indica un metodo che
// prende in ingresso una string e ritorna void
public delegate void MyEventHandler(string foo);

//Definisco un evento, che ha come tipo il delegate
//indicato sopra
public event MyEventHandler SomethingHappened;

// Quando l'evento chiamato SomethingHappened viene lanciato,
// eseguo questo codice, che rispecchia la firma
// del delegate descritto sopra
protected virtual void OnSomethingHappened(string foo)
{
    //Do some stuff
}

//Assegno un nuovo delegate che punta a OnSomethingHappened
// e lo aggiungo alla lista di eventi chiamata SomethingHappened
myObj.SomethingHappened += new MyEventHandler(OnSomethingHappened);

2.La parola chiave event

Per definire un evento, utilizzare event nella firma del metodo che genera l’evento e specificare il tipo di delegato questo ultimo.

In genere, per generare un evento, si aggiunge un metodo contrassegnato come protected e virtual chiamandolo OnEventName.

Il seguente esempio mostra come dichiarare un evento denominato ThresholdReached: l’evento viene associato al delegato con il EventHandler e viene generato in un metodo denominato OnThresholdReached.

class Counter
{
    public event EventHandler ThresholdReached;

    protected virtual void OnThresholdReached(EventArgs e)
    {
        EventHandler handler = ThresholdReached;
        if (handler != null)
        {
            handler(this, e);
        }
    }

    // provide remaining implementation for the class
}

3. Utilizzare i delegate del .NET

Negli esempi precedenti non abiamo posto particolare attenzione sulla firma che deve avere il delegate; .NET consiglia di seguire però questo standard per la definizione dei delegate:

delegate void MyEventHandler(object sender, EventArgs e);

quindi quando sollevo l’evento devo obbligatoriamente fornisce la classe che l’ha sollevato e degli argomenti di evento.

Il .NET fornisce un delegate apposito, chiamato EventHandler.

Il secondo argomento è un’istanza della classe EventArgs, si tratta di un tipo che non contiene aluna informazione ma la cui adozione è congliata per un requisito di forma che vedremo fra poco.

Il modo più semplice di valorizzarlo è tramite il suo campo statico Empty:

myMethod(this, EventArgs.Empty)

Qualora volessimo fornire all’evento ulteriori informazioni di stato, conviene creare una classe personalizzata che derivi da EventArgs il cui nome convenzionalmente termina con tale suffisso.

internal class ModeChangedEventArgs : EventArgs
{
    public ImageLogSettingMode Mode;
    public ModeChangedEventArgs(ImageLogSettingMode mode)
    {
        Mode = mode;
    }
}

Indice

Share
Ultimi articoli
Join

Newsletter

Nessuno spam, solo articoli interessanti ;)

Focus

Post correlati

semaphoreslim

SmaphoreSlim 101

SemaphoreSlim è una classe che permette la sincronizzazione di n thread che hanno una risorsa (scarsa) condivisa limitandone l’uso ad un numero massimo.

interlocked

Interlocked 101

La sincronizzazione dei thread è un elemento fondamentale nella programmazione asincrona, ne ho infatti parlato in vari post. La soluzione più versatile è sicuramente utilizzare

event

Come testare gli eventi

Testare che degli eventi siano stato effettivamente lanciati in C# non è immediato. Tipicamente è possibile testare che un evento venga lanciato aspettando un ManualResetEvent

Codice Pragmatico

Contatti

Per informazioni, dubbi o consulenze non esitate a contattarmi.

Lascia un messaggio

Ricevi le ultime news

Iscrivi alla newsletter

Solo articoli interessanti, promesso ;)