Delegati ed eventi
Fa parte della sezione Programmazione orientata agli oggetti del percorso C# di Coddy. Lezione 43 di 70.
Un delegato è un tipo che rappresenta un riferimento a un metodo. Consideralo come una variabile che contiene un metodo invece di dati. Questo ti consente di passare metodi come argomenti, memorizzarli in raccolte e chiamarli dinamicamente.
Dichiari un delegato specificando la firma del metodo a cui può fare riferimento:
public delegate void Notify(string message);
public class Publisher
{
public void SendAlert(string msg) => Console.WriteLine("Alert: " + msg);
}
// Utilizzo
Notify notifier = new Publisher().SendAlert;
notifier("System started"); // Alert: System startedGli eventi si basano sui delegati per implementare il modello publish-subscribe. Una classe genera un evento e altre classi possono iscriversi per ricevere notifiche. La parola chiave event limita il modo in cui è possibile usare il delegato: gli iscritti possono solo aggiungere o rimuovere gestori, non invocare direttamente l'evento.
public class Button
{
public event Action Clicked;
public void Click()
{
Clicked?.Invoke(); // Notifica tutti gli iscritti
}
}
// Iscrizione
Button btn = new Button();
btn.Clicked += () => Console.WriteLine("Button was clicked!");
btn.Click(); // Il pulsante è stato cliccato!L'operatore += sottoscrive un gestore, mentre -= annulla la sottoscrizione. Il modello ?.Invoke() richiama l'evento in modo sicuro solo se ci sono sottoscrittori. Gli eventi sono fondamentali nelle applicazioni GUI, nei motori di gioco e in qualsiasi sistema in cui gli oggetti devono reagire ai cambiamenti senza un accoppiamento stretto.
Sfida
FacileCostruiamo un sistema di monitoraggio della temperatura che usa delegati ed eventi per notificare gli iscritti ogni volta che la temperatura cambia. Questo è un classico esempio del modello publish-subscribe, che gli eventi rendono così elegante.
Organizzerai il codice in due file:
TemperatureMonitor.cs: crea una classeTemperatureMonitornello spazio dei nomiMonitoringche funge da editore. Il monitor dovrebbe:- Avere un campo privato in cui memorizzare la temperatura corrente
- Dichiarare un evento usando
Action<int>chiamatoTemperatureChanged, che viene attivato ogni volta che la temperatura viene aggiornata - Avere una proprietà
Temperature(int) il cui setter aggiorna il campo privato e attiva l'evento con il nuovo valore della temperatura
?.Invoke()per attivare l'evento in modo sicuro solo quando ci sono iscritti.Program.cs: nel file principale, crea unTemperatureMonitore iscrivi due gestori diversi al suo eventoTemperatureChanged:- Un gestore che stampa:
Alert: Temperature is now {value} degrees - Un altro gestore che stampa:
Logged: {value}
- Un gestore che stampa:
Riceverai due input:
- Primo valore della temperatura (intero)
- Secondo valore della temperatura (intero)
Per esempio, se gli input sono 25 e 30, l'output dovrebbe essere:
Alert: Temperature is now 25 degrees
Logged: 25
Alert: Temperature is now 30 degrees
Logged: 30Nota come l'impostazione della proprietà Temperature notifichi automaticamente tutti gli iscritti: il monitor non deve sapere nulla di chi sta ascoltando. Questa è la bellezza dell'approccio basato sugli eventi!
Provalo tu
using System;
using Monitoring;
class Program
{
public static void Main(string[] args)
{
// Leggi l'input
int temp1 = Convert.ToInt32(Console.ReadLine());
int temp2 = Convert.ToInt32(Console.ReadLine());
// TODO: Crea un'istanza di TemperatureMonitor
// TODO: Registra un gestore che stampi: "Alert: Temperature is now {value} degrees"
// TODO: Registra un altro gestore che stampi: "Logged: {value}"
// TODO: Imposta la temperatura su temp1
// TODO: Imposta la temperatura su temp2
}
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Fondamenti della programmazione orientata agli oggetti
File esterniNamespace e direttiveIntroduzione a classi e oggettiLa parola chiave "this"Metodi e parametriCampi e proprietàCostruttoriInizializzatori di oggettiRiepilogo - Calcolatrice semplice4Ereditarietà
Sintassi di base dell'ereditarietà (:)La parola chiave 'base'Parole chiave virtual e overrideClassi sealedLa classe base 'object'Riepilogo - Gerarchia dei dipendenti7Funzionalità avanzate
Sovraccarico degli operatoriIndicizzatori (this[])Override di ToString()Metodi di estensioneRiepilogo - Lista personalizzata10Pattern di progettazione Parte 1
Introduzione ai pattern di progettazioneSingleton thread-safePattern FactoryPattern Observer (eventi)Pattern Strategy2Proprietà e membri statici
Proprietà implementate automaticamenteProprietà di sola lettura e di sola scritturaCampi e metodi staticiClassi staticheMembri con corpo di espressione5Polimorfismo e interfacce
Polimorfismo a compile time e runtimeInterfaccia o classe astrattaInterfacce multipleInterfacce espliciteUpcasting e downcastingRipasso: calcolatore di forme8Concetti avanzati di programmazione a oggetti
Composizione invece dell'ereditarietàTipi generici (classi e metodi)Delegati ed eventiAttributi e reflectionIDisposable e istruzione usingNozioni di base sull'iniezione delle dipendenze11Pattern di progettazione, parte 2
Pattern del ComandoPattern dell’AdattatorePattern del DecoratorePattern Template MethodPattern dello StatoPattern Composito3Architettura delle classi
Dati di istanza vs staticiParole chiave 'readonly' e 'const'Campi di supportoRiepilogo - Gestore di conti bancari6Incapsulamento
Modificatori di accessoProprietà per l'incapsulamentoImplementazione dell'occultamento dei datiModelli di immutabilitàRiepilogo - Registri degli studentiEsercitati da solo: Compilatore C# online