Tuesday, April 30, 2024 07:04

Cuprins >> Delegați, Expresii Lambda, Evenimente > Func și Action

Func și Action

Există cinci tipuri de delegați prestabiliți pe care îi puteți utiliza în C#: Delegate, MulticastDelegate, Predicate, Func și Action. Am descris deja Delegate într-o lecție anterioară. MulticastDelegate există doar din motive istorice și de compatibilitate anteriorară, și ne permite să înlănțuim delegați, dar nu îl veți folosi în mod direct aproape niciodată. Func, Action și Predicate sunt tipuri generice de delegați care ne permit, practic, să declaram orice fel de delegat dorim, într-o manieră generică. Haideți să declaram câțiva:

În acest moment, codurile nu vă vor spune multe, avem doar niște variabile ciudate, de tip nou. Cu toate acestea, dacă așezăm cursorul asupra uneia din ele și apăsăm tasta F12, sau dacă facem clic dreapta pe ele și alegem „Go to definition”, astfel:

veți vedea această definiție pentru Action:

și aceasta pentru Func:

Deci, dacă citiți lecția mea despre delegați, nu ar trebui să vă fie greu să înțelegeți cel puțin Action. Este doar un delegat normal, care acceptă orice metodă care returnează void. Func este un pic mai dificil, pentru că este un tip de delegat generic, dar nu ar trebui să fie greu de înțeles dacă citiți lecția despre tipurile generice. Oricum, Func este un delegat care preia orice metodă care returnează ceva. Asa:

Deci, de fiecare dată când aveți nevoie de un delegat care acceptă orice metodă care returnează void, puteți utiliza întotdeauna Action. Ori de câte ori aveți nevoie de un delegat care preia orice metodă care returnează ceva, folosești Func cu tipul acelui ceva (bool în exemplul meu de mai sus)

Desigur, atât Action, cât și Func au supraîncărcări, ceea ce înseamnă că le putem atribui metode care iau unul sau mai mulți parametri. De exemplu:

În acest caz, am vrut să atribui o metodă care să returneze void, și să accepte doi parametri, unul de tip int, unul de tip string, void OMetodaCareReturneazaVoid (int, string). Pentru asta, tot ce am avut de făcut a fost să modific declarația mea Action pentru a accepta un int și un string: Action <int, string> _action. De fapt, Action are 16 suprasarcini, deci, puteți declara acțiuni care acceptă metode care au între 0 și 16 parametri și returnează void. Acest lucru este mai mult decât suficient pentru orice situație pe care o puteți întâlni.

Func, la fel ca și Action, are tot 16 supraîncărcări, și la fel ca și în cazul Action, îi puteți atribui orice metodă care returnează ceva și are între 0 și 16 parametri de orice tip. Diferența constă în faptul că, deoarece Func trebuie să returneze efectiv o valoare, și din moment ce este proiectată într-un mod generic, trebuie să specificăm și tipul de returnare, astfel încât compilatorul să știe ce fel de metode îi putem atribui (metodele trebuie să returneze același tip cu semnătura delegatului). Cu alte cuvinte, acesta este motivul pentru care am declarat Func în acest fel: Func<bool> _func. Chiar dacă funcția mea acceptă orice metodă care nu are parametri, trebuie să returneze ceva și sunt obligată să specific ce ar trebui să returneze. În acest caz, am ales să returneze o valoare booleană, dar aș putea specifica orice tip doresc.

Dacă trebuie să alocăm unei Func o metodă care preia și parametri, îi specificăm la fel cum îi specificăm și în cazul Action. Cu toate acestea, în cazul Func, ultimul parametru este ÎNTOTDEAUNA tipul de returnare, nu un parametru al metodei alocate. Cu alte cuvinte, putem declara un Func astfel:

Din moment ce OMetodaCareReturneazaUnBoolean() acceptă un int și un string ca parametri și returnează un bool, atunci când o atribui la Func, trebuie să-l declar astfel: Func<int, string, bool>. Int și string sunt aceleași tipuri pe care metoda le ia ca parametri, în timp ce ultimul tip din declarația Func, despre care tocmai explicam că reprezintă întotdeauna tipul de returnare, este un bool, la fel ca tipul returnat de metoda atribuită acestuia.

Predicate este un alt delegat care este identic cu Func în toate aspectele, cu singura excepție a faptului că returnează doar valoari boolene, deoarece semnatura este aceasta:

Predicate există datorită faptului că a venit înainte de Func. Presupun că dacă mai genericul Func ar fi fost implementat mai întâi, Predicate nu ar exista deloc. În cele mai multe cazuri, nu ar trebui să aveți nevoie să îl utilizați. Predicate este folosit mai ales în liste pentru metode precum FindAll() sau RemoveAll().

Ca o concluzie la această lecție, ori de câte ori aveți nevoie de un delegat, îl puteți declara direct ca Delegate, sau puteți folosi Action ori de câte ori aveți nevoie să alocați metode care au între 0 și 16 parametri și returnează void, sau Func atunci când aveți nevoie de același lucru ca și în cazul Action, dar și de o valoare returnată.

Tags: , ,

Leave a Reply



Follow the white rabbit