per capire le differenze puoi guardare questi 2 esempi
Esempio con delegati (azione in questo caso che è un tipo di delegato che non restituisce valore)
public class Animal
{
public Action Run {get; set;}
public void RaiseEvent()
{
if (Run != null)
{
Run();
}
}
}
per usare il delegato dovresti fare qualcosa di simile
Animale animal= new Animal();
animal.Run += () => Console.WriteLine("I'm running");
animal.Run += () => Console.WriteLine("I'm still running") ;
animal.RaiseEvent();
questo codice funziona bene ma potresti avere alcuni punti deboli.
Ad esempio se scrivo questo
animal.Run += () => Console.WriteLine("I'm running");
animal.Run += () => Console.WriteLine("I'm still running");
animal.Run = () => Console.WriteLine("I'm sleeping") ;
con l'ultima riga di codice ho dovuto sovrascrivere i comportamenti precedenti solo con uno mancante +
(ho usato al +
posto di +=
)
Un altro punto debole è che ogni classe che usa la tua Animal
classe può rilanciare RaiseEvent
semplicemente chiamandola animal.RaiseEvent()
.
Per evitare questi punti deboli puoi usare events
in c #.
La tua classe di animali cambierà in questo modo
public class ArgsSpecial :EventArgs
{
public ArgsSpecial (string val)
{
Operation=val;
}
public string Operation {get; set;}
}
public class Animal
{
public event EventHandler<ArgsSpecial> Run = delegate{} //empty delegate. In this way you are sure that value is always != null because no one outside of the class can change it
public void RaiseEvent()
{
Run(this, new ArgsSpecial("Run faster"));
}
}
per chiamare eventi
Animale animal= new Animal();
animal.Run += (sender, e) => Console.WriteLine("I'm running. My value is {0}", e.Operation);
animal.RaiseEvent();
differenze:
- Non stai utilizzando una proprietà pubblica ma un campo pubblico (con eventi il compilatore protegge i tuoi campi da accessi indesiderati)
- Gli eventi non possono essere assegnati direttamente. In questo caso non puoi fare l'errore precedente che ho mostrato con l'override del comportamento.
- Nessuno al di fuori della tua classe può sollevare l'evento.
- Gli eventi possono essere inclusi in una dichiarazione di interfaccia, mentre un campo no
Appunti
EventHandler viene dichiarato come il seguente delegato:
public delegate void EventHandler (object sender, EventArgs e)
richiede un mittente (di tipo Object) e gli argomenti dell'evento. Il mittente è nullo se proviene da metodi statici.
Puoi usare anche EventHAndler
questo esempio che usiEventHandler<ArgsSpecial>
fare riferimento qui per la documentazione su EventHandler