Wednesday, April 24, 2019 03:58

Manipularea erorilor cu Try Catch

De obicei, atunci când o excepție este aruncată, programul se blochează sau începe să funcționeze defectuos. Din fericire, există o modalitate de a preveni acest lucru, care ne permite să executăm coduri care pot genera excepții și să continuăm totuși execuția în condiții de siguranță, în caz de eroare. Conceptul de programare care ne oferă această siguranță în caz de eșec se numește un bloc Try Catch. Structura de bază a unui bloc Try Catch arată astfel:

După cum puteți vedea, un bloc Try Catch este compus din două părți: un bloc try, unde am plasat codurile care ar putea genera excepții, și unul sau mai multe blocuri catch, în care gestionăm excepțiile prinse. TipExceptie trebuie să fie orice tip derivat din spațiul de nume System.Exception, sau programul nu se va compila. Puteți găsi unele dintre aceste tipuri în lecția despre excepții. Deoarece numeObiect este o variabilă ca orice altă variabilă, o putem folosi în interiorul blocului Catch pentru a obține informații legate de eroarea capturată.

În lecția anterioară, am avut acest cod, care încerca să citească un fișier care nu există pe disc:

Și ați văzut cum codul a generat o excepție atunci când am încercat să îl executăm. Să îl modificăm acum, astfel încât să utilizeze un bloc Try Catch pentru gestionarea erorilor. Pentru a face acest lucru, tot ce trebuie să facem este să înfășurăm codul din interiorul metodei ReadFile() în interiorul unui bloc Try și să rezolvăm excepțiile care pot apărea în blocul Catch.

Procedând astfel, programul nostru va funcționa puțin diferit. În primul rând, pentru că am împachetat codul în interiorul blocului Try Catch, atunci când StreamReader va fi inițializat cu un nume de fișier care nu există, acesta nu va mai face programul nostru să înceteze să funționeze. În schimb, de îndată ce blocul Try detectează că o instrucțiune ce aruncă o excepție, va opri executația în blocul său (codul rămas din blocul Try NU va mai fi executat, după ce o anumită instrucțiune a generat o excepție) și o va transfera imediat către blocul (sau blocurile) Catch. În acest moment, compilatorul va căuta ce tipuri de excepții sunt manipulate în interiorul blocului Catch. Dacă unul dintre acestea gestionează tipul de excepție care a fost aruncată, executarea va fi transferată la acel bloc Catch, unde va rula tot codul din interiorul acestuia.

În cazul nostru, deoarece constructorul StreamReader va arunca o FileNotFoundException, execuția va fi transferată în blocul Catch care gestionează tipurile de excepții FileNotFoundException. Dacă excepția ar fi fost de orice alt tip (de exemplu, fișier deja folosit sau permisiune insuficientă de accesare a acestuia), timpul de execuție .NET ar căuta un alt bloc Catch care să gestioneze acel tip de excepție sau un tip din care excepția este aruncată. Acest lucru se datorează faptului că excepțiile sunt clase, care pot fi organizate în ierarhii și pot moșteni una de la cealaltă (încă nu am învățat despre moștenire); astfel, FileNotFoundException este o excepție derivată din IOException, care este de asemenea derivată din ApplicationException, care este de asemenea derivată din Exception, etc. Dacă nu am fi specificat un handler FileNotFoundException, dar am fi specificat un handler IOException, am fi fost în continuare OK în cazul a unei excepții ridicate când încercăm să accesăm un fișier care nu există. Acest lucru se întâmplă deoarece IOException este o clasă de excepții care este „mai sus” în ierarhie față de cea FileNotFoundException, iar FileNotFoundException moștenește de la ea. Deci, putem spune că deoarece alte excepții moștenesc din IOException, IOException este capabilă să se ocupe de mai mult de un singur fel de excepție, la fel cum și clasa Exception (fiind tipul rădăcină al tuturor celorlalte tipuri de excepții, în partea cea mai de sus a ierarhiei) se pot ocupa de orice tip de excepție.

Deci, în cazul nostru, deoarece codul problematic a ridicat o excepție de tip FileNotFoundException și deoarece am declarat un bloc Catch care gestionează acest tip de excepții, execuția va fi transferată imediat în acest bloc special Catch. Ca parametru pentru această construcție Catch, vedem că are o variabilă numită efnf, de tip FileNotFoundException. La fel ca într-o funcție normală, putem folosi această variabilă parametru în interiorul blocului Catch:

În codul de mai sus, atunci când excepția FileNotFoundException este aruncată, folosim variabila efnf pentru a afișa mesajul la consolă, folosind metoda ToString(). Ar trebui să știți totuși, acest lucru nu este considerat o practică de programare bună, și am exemplificat-o doar pentru a vedea că variabila efnf poate fi utilizată în interiorul blocului Catch. În afară de aceasta, observați că în cadrul metodei CitesteFisier() gestionăm numai excepții de tipul FileNotFoundException. Dacă metoda ar fi aruncat vreun alt tip de excepție, aceasta ar fi fost trecută înapoi metodei Main(), care având și ea un bloc Try Catch care se ocupă direct de clasa Exception (rețineți, clasa Exception se află în partea de sus a ierarhiei, este părintele tuturor celorlalte excepții, și prin urmare, captează orice tip de excepție), manipulează excepția returnată de metoda ReadFile(). Cu toate acestea, după cum vom vedea într-o lecție viitoare, utilizarea clasei Exception în mod direct pentru a prinde orice tip de excepție este de asemenea considerată o practică de programare proastă.

Comments

comments

Tags: , , ,

Leave a Reply