Un delegat este un tip care descrie semnătura unei metode. O variabilă de tip delegat stochează o referință către o metodă compatibilă și poate fi invocată ca și cum ar fi metoda respectivă.
Invocare sigură — nu aruncă excepție dacă delegatul e null
Delegații sunt mecanismul de bază pe care se construiesc Action, Func și evenimentele.
Metode anonime și expresii lambda
Permit definirea unui comportament direct la locul utilizării, fără o declarație separată și fără un nume.
// Metoda anonima (C# 2.0)NotificareClientn=delegate(stringnr,stringmsg){Console.WriteLine("[PUSH] "+nr+": "+msg);};// Lambda echivalenta (C# 3.0) — forma preferataNotificareClientn=(nr,msg)=>Console.WriteLine("[PUSH] "+nr+": "+msg);
Concept
Ce înseamnă
delegate(...) { }
Sintaxa originală pentru metode anonime
(p1, p2) => expresie
Lambda cu mai mulți parametri
param => { ... }
Lambda cu corp din mai multe instrucțiuni
Closure
Lambda captează variabile din context ca referință, nu ca valoare
Lambda și -=
Lambda anonim nu poate fi dezabonat fără o referință stocată
Lambda-ul captează referința la variabilă, nu valoarea ei la momentul definirii. Dacă variabila se schimbă, lambda vede noua valoare.
Action, Func și Predicate
Delegați generici predefiniti în .NET care acoperă majoritatea scenariilor fără declarații custom.
Tip
Semnătură
Cazul de utilizare
Action
void ()
Fără parametri, fără retur
Action<T1, T2>
void (T1, T2)
Doi parametri, fără retur
Func<T, TResult>
TResult (T)
Un parametru, cu retur
Predicate<T>
bool (T)
Condiție de filtrare pentru List<T>
Predicate<T> și Func<T, bool> au aceeași semnătură dar sunt tipuri diferite. List<T>.FindAll() acceptă Predicate<T>, LINQ Where acceptă Func<T, bool>.
Multicast
Un delegat poate stoca referințe către mai multe metode simultan. La invocare, toate sunt apelate în ordinea adăugării.
Concept
Ce înseamnă
+=
Adaugă o metodă la lista delegatului
-=
Elimină o metodă din lista delegatului
Ordine de invocare
Metodele sunt apelate în ordinea adăugării, garantat
Valoare returnată
Doar valoarea ultimei metode este returnată; celelalte sunt ignorate
GetInvocationList()
Returnează toate metodele din listă pentru invocare manuală
?.Invoke(...)
Invocare sigură dacă lista e goală (null)
+= creează un delegat nou — delegații sunt imuabili. Dacă toate metodele sunt eliminate cu -=, variabila devine null.
Evenimente (event)
event restricționează accesul la un delegat: din exterior sunt permise doar += și -=. Invocarea și atribuirea directă sunt rezervate clasei proprietare.
Concept
Ce înseamnă
event
Restricționează accesul la delegat din exterior
Din exterior
Doar += și -= sunt permise
Din interior
Clasa proprietară poate invoca și atribui direct
?.Invoke(this, e)
Declanșare sigură — nu aruncă excepție dacă nu există abonați
EventHandler<T>
Delegatul standard pentru evenimente cu date de tip T
sender
Obiectul care a declanșat evenimentul
event adaugă encapsulare: numai clasa care deține evenimentul îl poate declanșa.
Evenimente cu date - EventArgs custom
Clasa EventArgs custom este un container de date transmis cu evenimentul.
Concept
Ce înseamnă
EventArgs custom
Clasă derivată din EventArgs cu datele relevante
EventHandler<T>
Delegatul predefinit: void Handler(object sender, T e)
OnNumeEveniment()
Metodă protected virtual care encapsulează declanșarea
Action<string, string> notificator = NotificareEmail;
Func<Comanda, double> livrare = comanda => 15.0;
Predicate<Comanda> filtru = comanda => comanda.GetValoareTotala() > 150;
Action<string, string> notificator = NotificareEmail;
notificator += NotificareSMS;
notificator += NotificareLog;
notificator("CMD-001", "Comanda expediata."); // apeleaza toate trei
class Depozit
{
public event EventHandler<ComandaSchimbatStareEventArgs> ComandaSchimbatStare;
public void AvansezaStare(string numarComanda)
{
// ...
ComandaSchimbatStare?.Invoke(this, new ComandaSchimbatStareEventArgs { ... });
}
}
depozit.ComandaSchimbatStare += OnComandaSchimbatStare; // OK
depozit.ComandaSchimbatStare = null; // eroare de compilare
depozit.ComandaSchimbatStare("CMD", args); // eroare de compilare
class ComandaSchimbatStareEventArgs : EventArgs
{
public Comanda Comanda { get; set; }
public StareComanda StareVeche { get; set; }
public StareComanda StareNoua { get; set; }
}
class ComandaLivrataEventArgs : EventArgs
{
public Comanda Comanda { get; set; }
public DateTime DataLivrare { get; set; }
public double CostLivrare { get; set; }
}