'Y'

ErrorProne.NET Ц partea II

In articolul trecut am discutat despre probleme legate de formatare. In acest articol ne vom uita peste exceptii. ErrorProne.Net a mostenit destul de multe caracteristici de la un alt proiect pe care l-am dezvoltat Ц ExceptionAnalyzer dar intr-o forma usor diferita. Include reguli precum:

May 13, 2016 1742
In articolul trecut am discutat despre probleme legate de formatare. In acest articol ne vom uita peste exceptii.

ErrorProne.Net a mostenit destul de multe caracteristici de la un alt proiect pe care l-am dezvoltat Ц ExceptionAnalyzer dar intr-o forma usor diferita. Include reguli precum:
  • ERP021 Ц propagarea unei exceptii incorecte: redirectionarea exceptiei УincorecteФ cu ajutorul throw ex; in loc de throw
  • ERP022 Ц o exceptie neobservata in generic exception handler: atunci cand exceptiile sunt identificate programul declara handler-ul fara a incerca sa УobserveФ exceptia identificata
  • ERP023 - tratarea suspicioasa a unei exceptii: doar proprietatea Message a fost observata: atunci cand catch block generalizat se refera doar la ex.Message exception attribute
Acum vom analiza aceste exceptii in detaliu.

Propagarea unei exceptii incorecte

Nu voi petrece foarte mult timp pe acesta problema. Daca ati fost la un interviu sau ati lucrat intr-o echipa mai mare, sunt sigur ca stiti diferenta intre throw.ex; si throw;.

ErrorProne.NET. Part 2_1.jpg

Nu sunt surprize aici. throw.ex va УspargeФ callstack-ul exceptiei initiale, aspect care ingreuneaza analiza log-ului si identificarea problemei. Din moment ce este o problema foarte cunoscuta, nu veti gasi foarte multe situatii de acest gen. In ciuda acestui lucru, am descoperit un exemplu de redirectionare discutabila a unei exceptii in codul Roslyn: CompilationWithAnalyzer.cs:602.

Exceptie neobservata in generic exception handler

Din moment ce acest instrument este utilizat pentru cele mai provocatoare zone, majoritatea regulilor legate de procesarea exceptiilor sunt simple, precise si foarte putin dificile. Astfel, oricat de mult ar incerca anumite persoane sa interzica toate catch(Exception) blocks in codul lor, este dificil de facut acest lucru in practica datorita prevalentei acestora. Dar pot si ar trebui sa fie prevenite daca aceste blocks declara handlerul fara a verifica exceptiile pe care le-au identificat.

Din acest motiv urmatorul cod ofera un avertisment:

ErrorProne.NET. Part 2_2.jpg

Orice referinta la variabila e din catch block (precum e.Message, ProcessExcpetion(e) etc.) УdeactiveazaФ aceasta regula. Dintr-un anume motiv, nu am crezut ca aceasta regula va aparea foarte des si am fost foarte surprins ca in codul Roslyn a fost declansata de mai mult de 60 de ori. Iata cateva exemple:

Da, aceeasi regula va fi declansata doar pentru blocks cum ar fi catch {}, catch(System.Exception) si catch(System.AggregateException). Pentru mai multe exceptii specifice, este normal sa avem ca rezultat handler-ul fara a face referinta la exception object.

Tratarea suspicioasa a unei exceptii

Ce poate fi mai rau decat o exceptie care nu a fost identificata? Inregistrarea incompleta a detaliilor exceptiei! De fiecare data cand scrii ex.Message in fisierul log, codul tau va esua in productie indicand TypeLoadException si s-ar putea sa stai peste program pentru a descoperi de ce in productie nu mai functioneaza cand mergea perfect pe PC-ul local. Si te vei uita peste log si inregistrarile din log precum "Exception has been thrown by the target of an invocation.", "The type initializer for 'MyAwesomeType' are o exceptie." sau "One or more errors occurred." si te vei gandi "Ce Dumnezeu s-a intamplat".

Desigur ca putem spune ca noi revizuim codul cat mai atent, ca static constructors nu ignora exceptiile, ca nu recunoastem TPL-ul sau ca, in general, scriem cod fara erori din start. Ca raspuns la aceste afirmatii eu ofer exemplul de mai jos pentru a arata ca exceptiile apar si in locuri unde majoritatea oamenilor nu se asteapta sa fie.

ErrorProne.NET. Part 2_3.jpg

Pe masura ce limitarea new() duce la utilizarea Activator .CreateInstance, orice exceptie in object construction dezvoltata cu ajutorul metodelor generalizate precum Create<T> va transforma exceptia initiala intr-o TargetInvocationException. Acest gen de lucruri sunt usor de trecut cu vederea atunci cand revizuim dar este mult mai usor sa impachetam in orice cod care scrie doar un mesaj de exceptie si nu arata stacktrace + exceptii interne.

Din nou, am fost surprins de numarul de dati in care aceasta regula a fost incalcata in codul Roslyn. Sunt mai mult de 12 incalcari de reguli. Multe din ele sunt greseli de ortografie evidente, cum ar fi atunci cand o exceptie noua a fost generata, si au uitat sa defineasca vechea exceptie ca find embedded.

Sergey Teplyakov
Expert in .Net, —++ and Application Architecture

Daca iti place acest articol, distribuie-l si prietenilor tai!




Mai ai intrebari?
Contacteaza-ne.
Thank you.
Your request has been received.