Wednesday, June 19, 2019 01:19

Metode generice

Metodele generice, ca și clasele generice, sunt metode parametrizate (tipizate) pe care le folosim atunci când nu putem specifica tipul parametrilor metodei. De asemenea, la fel ca în cazul claselor generice, înlocuirea tipurilor necunoscute cu tipuri specifice se întâmplă la apelarea metodei.

Tipizăm o metodă atunci când adăugăm <K> după nume și înainte de acolada de deschidere a metodei, unde K înlocuiește tipul care va fi folosit ulterior.

Putem folosi tipul necunoscut K pentru parametrii din lista de parametri a metodei (<parametri>), al cărui tip este necunoscut și de asemenea, pentru valoarea returnată sau pentru a declara variabile de tip substitut K în corpul metodei.

De exemplu, să luăm în considerare o metodă efectuează înlocuirea valorilor a două variabile:

Aceasta este o metodă care schimbă valorile a două variabile fără a fi interesată de tipurile acestora. De aceea o definim ca o metodă generică, pentru a o putea folosi pentru toate tipurile de variabile.

Prin urmare, acum o putem folosi pentru a schimba de exemplu numere întregi și șiruri de caractere:

La rulare, rezultatul ar fi acesta:

metode generice

Analizând codul, observăm cuvântul cheie ref, despre care nu am învățat încă. Imaginați-vă pentru moment că îl folosim pentru a păstra modificările valorilor variabilelor după ce metoda respectivă își încheie execuția.

În afară de aceasta, ar trebui să știți că prin apelarea unei metode generice puteți să omiteți declararea explicită a unui anumit tip (în exemplul nostru), deoarece compilatorul îl va detecta automat, recunoscând tipul respectivilor parametri. Cu alte cuvinte, codul nostru poate fi simplificat, folosind următoarele apeluri:

Compilatorul va putea recunoaște tipul specific numai dacă acest tip este implicat în lista parametrilor. Compilatorul nu poate recunoaște care este tipul specific al unei metode generice numai după tipul valorii returnate sau dacă aceasta nu are parametri. În ambele cazuri, acest tip specific va trebui să fie specificat în mod explicit. În exemplul nostru, ar fi similar cu apelul metodei inițiale, sau cu adăugarea <int> sau <string>.

Metodele statice pot fi și ele tipizate, spre deosebire de proprietățile și constructorii clasei.

În lecția noastră despre clase generice am avut următorul exemplu de clasă generică cu două metode generice:

Dacă încercăm să reutilizăm variabila, care este folosită pentru a marca tipul necunoscut al clasei generice, de exemplu ca T, în declarația metodei generice, atunci când încercăm să compilăm clasa, vom primi un avertisment: Parametrul tip „T” are același nume ca și parametrul de tip din tipul exterior „CommonOperations <T>” (Type parameter ‘T’ has the same name as the type parameter from outer type ‘CommonOperations<T>’).

Acest lucru se întâmplă deoarece domeniul de acțiune al tipului necunoscut T, definit în declarația metodei, se suprapune domeniului de acțiune al tipului necunoscut T, în declarația de clasă:

Prin urmare, dacă dorim să avem un cod flexibil și metoda noastră generică să fie apelată în siguranță cu un tip specific, diferit de cel din clasa generică declarat la momentul instanțierii sale, trebuie doar să declarăm înlocuitorul tipului necunoscut În declarația metodei generice să fie diferit de parametrul pentru tipul necunoscut din declarația de clasă, după cum se arată mai jos:

Prin urmare, asigurați-vă întotdeauna că nu vor exista suprapuneri ale inlocuitorilor tipurilor necunoscute de metodă și de clasă.

Deci! Acum, că am învățat atât despre clase generice și metode, să luăm exemplul adăpostului nostru de animale din lecția anterioară și să îl re-codăm folosind ambele concepte noi:

Primul lucru pe care îl observăm este faptul că bucata de cod de mai sus generează o eroare de compilator: Nu pot converti null în tipul parametrului ‘T’ deoarece ar putea fi un tip de valoare non-nullable. Luați în considerare utilizarea ‘default(T)’ în schimb (Cannot convert null to type parameter ‘T’ because it could be a non-nullable value type. Consider using ‘default(T)’ instead).

Eroarea se află în interiorul metodei Elibereaza() și este legată de înregistrarea unei valori nule în ultima celulă eliberată (cea mai din dreapta) din adăpost. Problema este că încercăm să folosim valoarea implicită pentru un tip de referință, dar nu știm cu siguranță dacă acest tip este un tip de referință sau unul primitiv. Prin urmare, compilatorul afișează eroarea de mai sus. Dacă tipul AdapostAnimale este instanțiat de o structură și nu de o clasă, atunci valoarea nulă nu este validă.

Pentru a rezolva această problemă, trebuie să folosim în codul nostru constructul default(T) în loc de null, care returnează valoarea implicită pentru tipul particular care va fi folosit în loc de T. După cum știm, valoarea implicită pentru tipul de referință este null, iar pentru tipurile numerice – zero. Putem face următoarea modificare:

În cele din urmă, compilarea rulează fără probleme și clasa AdapostAnimale funcționează corect. Putem testa acest lucru după cum urmează:

În concluzie, din ultimele două lecții: clasele generice și metodele generice sporesc reutilizarea, securitatea și performanța codului, comparativ cu alte alternative non-generice. Ca regulă generală, programatorii ar trebui să se străduiască să creeze și să folosească clase generice ori de câte ori este posibil. Cu cât sunt folosite mai multe tipuri generice, cu atât se atinge un nivel superior de abstractizare în program, iar codul sursă devine mai flexibil și reutilizabil. Cu toate acestea, ar trebui să rețineți că utilizarea excesivă a elementelor generice poate duce la o generalizare exagerată, iar codul poate deveni greu de înțeles și descifrat de către alți programatori.

Comments

comments

Tags: , , ,

Leave a Reply