Thursday, April 25, 2024 08:27

Cuprins >> Delegați, Expresii Lambda, Evenimente > Expresii lambda

Expresii lambda

În lecția anterioară scriam că putem îmbunătăți în continuare codul folosind expresii lambda. O expresie lambda este o modalitate convenabilă de a defini o funcție anonimă (fără nume) care poate fi transmisă ca variabilă sau ca parametru la un apel de metodă. Pentru început, acesta era codul cu care am rămas în lecția anterioară:

Deci, cele trei metode pe care le-am declarat candidate la delegatul FilterDelegate, MaiMicDeCinci, MaiMicDeZece, MaiMareDeTreisprezece, sunt foarte similare una cu alta. Ori de câte ori avem coduri care arată izbitor de similar, facem ceva greșit. De fapt, ce diferă în cele trei metode? Dacă analizați sintaxa, veți observa că singura diferență vine în această bucată de cod: _numar <5 ;. Asta este tot ceea ce avem cu adevărat nevoie de la aceste metode, și asta este tot ceea ce este relevant și trebuie să fie parametrizat.

O expresie lambda ne permite să declaram o metodă fără un nume care este utilizată într-un singur loc și este declarată local. Și, dacă ne uităm la codurile noastre, folosim cele trei metode într-un singur loc, ca parametru al metodei FiltreazaNumere. Deci, dacă o expresie lambda este declarată doar la nivel local, să facem exact asta, să mutăm una dintre declarațiile metodelor noastre în locul în care avem nevoie de fapt de ea:

În acest moment, veți primi erori de compilare, dar ignorați-le, vom clarifica puțin lucrurile. Deoarece, dacă stați să vă gândiți, cuvântul cheie static nu are niciun sens în contextul local, deci, îl putem șterge:

În continuare, cuvântul cheie bool, care ne spune tipul de returnare al metodei: ei, bine, pot privi această expresie și văd că în mod evident, returnează o valoare booleană: _numar <5. Deci, nu am nevoie nici de cuvântul cheie bool:

Acum, metoda MaiMicDeCinci, întrucât o convertim într-o expresie lambda, iar expresiile lambda sunt declarate și utilizate doar local, există doar în bucata de cod unde o declarăm, direct în interiorul apelului la funcția FiltreazaNumere. Nu o vom apela nicăieri altundeva. Deci, nu avem nevoie de un nume nici pentru acesta:

Vedem că declarația afirmă că _numar este un int. Știu deja că este un int, deoarece DelegatFiltru primește un int. Trecem metoda noastră ca parametru la parametrul DelegatFiltru al metodei FiltreazaNumere, iar FiltreazaNumere preia un int. Nu prea trebuie să specific tipul variabil _numar:

Am voie să păstrez parantezele acestei expresii: (_numar), dar parantezele în acest context mi-ar permite doar să pun mai mult de un argument. Din moment ce am doar argumentul _numar, nu prea am nevoie de acestea:

Acum, cuvântul cheie return, am o singură expresie în cadrul acestei metode, deci compilatorul poate deduce și ce să returneze. Îl pot elimina:

Dacă metoda mea ar fi avut mai mult de o declarație, aș fi fost forțată să scriu declarația return, astfel încât compilatorul să înțeleagă care dintre declarații trebuie returnată.

Am spus deja că avem o singură afirmație, și puteți vedea că folosim acolade. Vă amintiți că acoladele definesc doar un bloc de cod care ne permite să scriem mai multe enunțuri, nu? Deci, dacă am o singură instrucțiune, le pot elimina și de asemenea, pot elimina punctul și virgula de la sfârșitul afirmației mele, deoarece un punct și virgulă doar separă mai multe instrucțiuni una de alta:

În această etapă, s-ar putea să vă gândiți că am ciopârțit metoda atât de mult încât n-a mai rămas cine știe ce din ea. Și ați avea dreptate, iar asta este de fapt tot ce avem nevoie din această metodă. Avem nevoie de _numar, deoarece este numele argumentului pe care îl utilizăm pentru a trece parametrii la funcția noastră ciopârțită, și expresia în sine, _numar <5, care folosește numitul argument și returnează o valoare. Poate fi evident faptul că, evident, compilatorul trebuie să știe unde se termină argumentul(ele) metodei noastre și unde începe corpul său, și faptul că nu putem folosi o virgulă sau ceva de genul acesta, deoarece ar părea că trecem încă o altă parametru, separat prin virgulă. În schimb, C# ne oferă un simbol special pe care l-a moștenit din alte limbaje funcționale, un semn egal urmat de o săgeată la dreapta:

Această bucată de cod este de fapt o expresie lambda: _numar => _numar <5. Să vă traduc sintaxa: „folosește variabila _numar ca parametru de metodă, trimite acest parametru la această expresie, și dă-mi valoarea pe care o returnează expresia”. Sau, forma scurtată, „folosește _numar și spune-mi când _numar este mai mic de cinci”. Sau, cea mai scurtă formă, „_numar unde _numar este mai mic de 5″.

Dacă o integrez în codurile mele în această etapă:

tot primesc numerele mai mici de cinci:

Este minunat că nu suntem obligați să declaram cele trei metode la începutul clasei noastre. Acum, doar schimbăm un semn și o valoare, pentru a schimba complet numerele pe care le filtrăm.

Dacă aveți vreodată nevoie de o expresie lambda care nu preia argumente, sunteți obligați să specificați două paranteze, astfel:

În acest caz, am declarat variabila i în afara expresiei lambda, în interiorul corpului metodei mele Main. Prin urmare, nu a fost nevoie să declar o expresie lambda care să accepte niciun parametru, deoarece în interiorul corpului său incrementez valoarea declarată extern. Totuși, a trebuit să folosesc () când am declarat expresia lambda, astfel încât compilatorul să înțeleagă că aceasta nu are parametri.

Dacă doriți să știți ce se întâmplă sub capotă, expresiile lambda nu funcționează în MSIL. Când compilatorul vede o expresie lambda, acesta o va converti într-o metodă normală:

Metodă generată de MSIL pentru expresie lambda, în C#

Deci, când vă gândiți la expresii lambda, gândiți-vă la ele ca la metode. Dar, ceea ce e interesant, gândiți-vă la ele ca metode fără nume. Nu ne interesează numele, pentru că le folosim o singură dată, acolo unde sunt declarate. Acesta este motivul pentru care unii programatori le numesc metode anonime, chiar dacă metodele anonime sunt un concept diferit în C#.

Tags: , , , , ,

Leave a Reply



Follow the white rabbit