Kako podesiti pametne telefone i računare. Informativni portal
  • Dom
  • Savjet
  • Tipične greške u C kodu Sharp. Otklanjanje grešaka i rukovanje izuzetcima

Tipične greške u C kodu Sharp. Otklanjanje grešaka i rukovanje izuzetcima

Osnove rukovanja izuzecima

Greške nisu uvijek krive osobe koja kodira aplikaciju. Ponekad aplikacija generiše grešku zbog radnji krajnjeg korisnika ili je greška uzrokovana kontekstom okruženja u kojem se kod izvodi. U svakom slučaju, uvijek biste trebali očekivati ​​da će se greške pojaviti u vašim aplikacijama i kodu u skladu s tim očekivanjima.

.NET Framework pruža napredno rukovanje greškama. C#-ov mehanizam za rukovanje greškama omogućava vam da kodirate prilagođeno rukovanje za svaki tip stanja greške, kao i da odvojite kod koji potencijalno generiše greške od koda koji ih obrađuje.

Šta god da uzrokuje problem, aplikacija na kraju ne radi kako se očekivalo. Prije nego što pogledamo strukturirano rukovanje iznimkama, upoznajmo se s tri najčešće korištena termina za opisivanje anomalija:

Softverske greške (greške)

Ovo je obično ime koje se daje greškama programera. Na primjer, recimo da gradite aplikaciju koristeći neupravljani C++. Ako se dinamički dodijeljena memorija ne oslobodi, što rezultira curenjem memorije, pojavljuje se softverska greška.

Korisničke greške

Za razliku od softverske greške, korisničke greške obično nastaju od onih koji pokreću aplikaciju, a ne od onih koji je kreiraju. Na primjer, krajnji korisnik koji unese pogrešno formatiran niz u tekstualno polje može generirati ovu vrstu greške ako kod nije dizajniran za rukovanje nevažećim unosom.

Izuzeci

Izuzeci ili izuzetne situacije se obično nazivaju anomalijama koje se mogu pojaviti tokom izvršavanja i koje je teško, ako ne i nemoguće, predvidjeti prilikom programiranja aplikacije. Mogući izuzeci uključuju pokušaje povezivanja na bazu podataka koja više ne postoji, pokušaje otvaranja oštećen fajl ili pokušava uspostaviti komunikaciju sa mašinom koja je trenutno unutra vanmrežni način rada. U svakom od ovih slučajeva, programer (i krajnji korisnik) može malo učiniti u vezi s takvim „izuzetnim“ okolnostima.

Iz gornjih opisa bi trebalo biti jasno da strukturirano rukovanje izuzetcima u .NET-u je tehnika dizajnirana za rukovanje izuzecima koji se mogu pojaviti u vremenu izvođenja. Međutim, čak i u slučaju softverskih i korisničkih grešaka koje izmiču oku programera, CLR će često automatski izbaciti odgovarajući izuzetak s opisom trenutni problem. Postoji mnogo različitih izuzetaka definisanih u bibliotekama osnovnih klasa .NET, kao što su FormatException, IndexOutOfRangeException, FileNotFoundException, ArgumentOutOfRangeException, itd.

U .NET terminologiji, "izuzetak" se odnosi na softverske greške, korisničke greške i greške u izvršavanju. Prije nego što uđemo u detalje, pogledajmo ulogu strukturiranog rukovanja izuzecima i kako se ono razlikuje od tradicionalnih tehnika rukovanja greškama.

Uloga rukovanja izuzecima u .NET-u

Prije .NET-a, rukovanje greškama u operativnom okruženju Windows sistemi bila je vrlo zbunjujuća mješavina tehnologija. Mnogi programeri su uključili vlastitu logiku rukovanja greškama u kontekstu aplikacije od interesa. Na primjer, razvojni tim bi mogao definirati skup numeričkih konstanti za predstavljanje poznatih situacija kvara, a zatim koristiti ove konstante kao povratne vrijednosti metode.

Osim tehnika koje su izmislili sami programeri, Windows API definira stotine kodova grešaka koristeći #define i HRESULT, kao i mnoge varijacije jednostavnih Booleovih vrijednosti (bool, BOOL, VARIANT BOOL, itd.). Štaviše, mnogi programeri COM aplikacija u C++ (i takođe VB 6) eksplicitno ili implicitno koriste mali skup standardnih COM interfejsa (poput ISupportErrorInfo.IErrorInfo ili ICreateErrorInfo) da vrate razumljive informacije o grešci COM klijentu.

Očigledan problem sa svim ovim starijim tehnikama je nedostatak simetrije. Svaki od njih se manje-više uklapa u okvir jedne tehnologije, jednog jezika, a možda i jednog projekta. .NET podržava standardnu ​​tehniku ​​za generiranje i otkrivanje runtime grešaka tzv strukturirano rukovanje izuzetcima (SEH) .

Ljepota ove tehnike je u tome što omogućava programerima da koriste jedinstven pristup rukovanju greškama koji je zajednički za sve .NET-bazirane jezike. Zbog toga, C# programer može rukovati greškama na isti sintaktički način kao VB programer i C++ programer koristeći C++/CLI.

Dodatna prednost je da je sintaksa koju trebate koristiti za izbacivanje i hvatanje izuzetaka izvan sklopova i strojeva također identična. Na primjer, kada pišete na C# Windows usluge Communication Foundation (WCF) može izbaciti SOAP izuzetak udaljenom pozivaocu korištenjem istih ključnih riječi koje se koriste za izbacivanje izuzetka unutar metoda u istoj aplikaciji.

Posljednje ažuriranje: 23.10.2018

Ponekad se prilikom izvršavanja programa javljaju greške koje je teško predvidjeti ili predvidjeti, a ponekad čak i nemoguće. Na primjer, prilikom prijenosa datoteke preko mreže, mrežna veza može neočekivano prekinuti. takve situacije se nazivaju izuzecima. C# jezik pruža programerima mogućnosti da se nose sa takvim situacijama. Konstrukt try...catch...finally u C# je dizajniran za ovo.

Pokušajte ( ) uhvatiti ( ) konačno ( )

Kada koristite blok try...catch..finally, svi izrazi u bloku try se prvo izvršavaju. Ako se u ovom bloku ne pojave iznimke, tada nakon njegovog izvršenja počinje da se izvršava finally blok. I onda pokušaj..uhvati..konačno završi svoj posao.

Ako se iznenada dogodi izuzetak u bloku try, normalni nalog izvršenja se zaustavlja i CLR počinje tražiti blok catch koji može podnijeti ovaj izuzetak. Ako potreban blok catch je pronađen, zatim se izvršava, a nakon što se završi, izvršava se finally blok.

Ako potrebni blok za hvatanje nije pronađen, onda kada se dogodi izuzetak, program nenormalno prekida svoje izvršavanje.

Razmotrite sljedeći primjer:

Program klase ( statički void Main(string args) (int x = 5; int y = x / 0; Console.WriteLine($"Rezultat: (y)"); Console.WriteLine("Kraj programa"); Console.Read (); ) )

IN u ovom slučaju broj je podijeljen sa 0, što će generirati izuzetak. A kada pokrenemo aplikaciju u načinu za otklanjanje grešaka, vidjet ćemo Visual Studio prozor koji obavještava o izuzetku:

U ovom prozoru vidimo da se dogodio izuzetak, koji je tipa System.DivideByZeroException, odnosno pokušaj dijeljenja sa nulom. Koristeći stavku Prikaži detalje, možete vidjeti više detaljne informacije o izuzetku.

I u ovom slučaju nam jedino preostaje da završimo program.

Da bi se ovo izbjeglo crash programe, trebali biste koristiti try...catch...finally konstrukciju za rukovanje izuzecima. Dakle, prepišimo primjer na sljedeći način:

Class Program ( static void Main(string args) (pokušajte (int x = 5; int y = x / 0; Console.WriteLine($"Result: (y)"); ) catch ( Console.WriteLine("Dogodio se izuzetak ! "); ) konačno ( Console.WriteLine("Konačno blok"); ) Console.WriteLine("Kraj programa"); Console.Read(); ) )

U ovom slučaju, opet ćemo imati izuzetak u bloku try, jer pokušavamo podijeliti sa nulom. I stići do linije

Int y = x / 0;

izvršenje programa će se zaustaviti. CLR će pronaći blok za hvatanje i prenijeti kontrolu na taj blok.

Nakon catch bloka, finally blok će biti izvršen.

Dogodio se izuzetak! konačno blokirati Kraj programa

Dakle, program i dalje neće izvršiti dijeljenje na nulu i stoga neće ispisati rezultat ovog dijeljenja, ali sada se neće srušiti, a izuzetak će biti obrađen u bloku catch.

Treba napomenuti da ova konstrukcija zahtijeva blok try. Ako imamo blok catch, možemo izostaviti finally blok:

Pokušajte ( int x = 5; int y = x / 0; Console.WriteLine($"Rezultat: (y)"); ) catch ( Console.WriteLine("Dogodio se izuzetak!"); )

Suprotno tome, ako imamo finally blok, možemo izostaviti catch blok i ne obrađivati ​​izuzetak:

Pokušajte ( int x = 5; int y = x / 0; Console.WriteLine($"Rezultat: (y)"); ) konačno ( Console.WriteLine("Konačno blok"); )

Međutim, iako je takva konstrukcija sasvim ispravna sa stajališta C# sintakse, ipak, pošto CLR ne može pronaći potrebni blok za hvatanje, izuzetak neće biti obrađen i program će se srušiti.

Rukovanje izuzecima i uvjeti

Red izuzetne situacije može predvidjeti programer. Na primjer, neka program uključuje unos broja i izlaz njegovog kvadrata:

Static void Main(string args) ( Console.WriteLine("Unesite broj"); int x = Int32.Parse(Console.ReadLine()); x *= x; Console.WriteLine("Kvadratni broj: " + x) ; Console.Read(); )

Ako korisnik unese ne broj, već niz ili neke druge znakove, program će ispisati grešku. S jedne strane, ovo je upravo situacija kada možete koristiti try..catch blok za obradu moguća greška. Međutim, bilo bi mnogo optimalnije provjeriti valjanost konverzije:

Static void Main(string args) ( Console.WriteLine("Unesite broj"); int x; string input = Console.ReadLine(); if (Int32.TryParse(input, out x)) ( x *= x; Konzola WriteLine("Kvadrat broja: " + x); ) else ( Console.WriteLine("Invalid input"); ) Console.Read(); )

Metoda Int32.TryParse() vraća true ako se konverzija može izvršiti, i false ako ne može. Ako je konverzija važeća, varijabla x će sadržavati uneseni broj. Dakle, bez korištenja try...catch, možete riješiti mogući izuzetak.

Sa stanovišta performansi, korištenje try..catch blokova je skuplje od korištenja uvjetnih. Stoga, ako je moguće, umjesto probati..catch bolje je koristiti kondicionale da proverite izuzetke.

konstante uslovne kompilacije. Omogućava vam da definirate konstante koje se kasnije koriste u metodi uvjetnog ispisa WriteIf klasa Debug i Trace. Snaga ovog mehanizma je u tome što se konstante mogu mijenjati u konfiguracijskoj datoteci projekta bez promjene projektnog koda ili potrebe da se ponovo kompajlira.

Visual Studio .Net Debugging i Workbench

Instrumentalno okruženje studija pruža programeru najviše širok raspon mogućnosti praćenja toka proračuna i praćenja stanja u kojima se proces proračuna nalazi. Jer svi su moderni instrumentalna okruženja organizovani na sličan način i dobro poznati programerima koji rade, dozvoliću sebi da se ne zadržavam na opisu mogućnosti okruženja.

Obrada izuzetaka

Kako god pouzdan kod bez obzira na to koliko je temeljno napisano, bez obzira na to koliko je detaljno otklanjanje grešaka, verzija koja je prebačena u rad i održavanje će naići na kršenje specifikacija tokom pokretanja. Razlog tome su gore navedeni zakoni softverski inženjeri. Ostaje u sistemu poslednja greška, postoje korisnici koji ne znaju specifikacije, a ako specifikacija može biti prekršena, onda će se ovaj događaj jednom dogoditi. Takve izuzetne situacije nastavak izvršavanja programa ili ono postane nemoguće (pokušaj neovlaštenog dijeljenja nultom operacijom, pokušaj upisivanja u zaštićeno memorijsko područje, pokušaj otvaranja nepostojeći fajl, pokušaj da se dobije nepostojeći zapis baze podataka), ili u nastaloj situaciji, upotreba algoritma će dovesti do pogrešnih rezultata.

Šta učiniti ako se to dogodi izuzetna situacija? Naravno da uvek postoji standardni način- prijaviti grešku i prekinuti izvršavanje programa. Jasno je da je ovo prihvatljivo samo za bezopasne aplikacije; čak i za kompjuterske igrice Ova metoda nije prikladna, a kamoli za kritične aplikacije!

U programskim jezicima za obradu izuzetne situacije ponudio najviše različiti pristupi.

Rukovanje izuzecima u C/C++ jezicima

Programski stil C karakteriše opisivanje metoda klase kao Booleove funkcije, vraća true ako se metoda normalno završava i false ako se dogodi izuzetna situacija. Poziv metode je ugrađen u if naredbu koja obrađuje grešku ako metoda ne uspije da se dovrši:

bool MyMethod(...)(...) if !MyMethod())(// rukovanje greškama) (//normalno izvršavanje)

Nedostaci ove šeme su jasni. Prvo, postoji malo informacija o uzroku greške, tako da ili kroz polja klase ili kroz argumente metode morate proći Dodatne informacije. Drugo, blok za obradu je ugrađen u svaki poziv, što dovodi do naduvavanja koda.

Stoga C/C++ koristi blok shemu try/catch, čija je suština sljedeća. Odjeljak programa u kojem se može pojaviti izuzetna situacija, je formatiran kao zaštićeni blok pokušaja. Ako prilikom njegovog izvršavanja postoji izuzetna situacija, tada je izvođenje bloka try s klasifikacijom izuzetaka prekinuto. Ovaj izuzetak počinje da se obrađuje od strane jednog od blokova catch koji odgovara tipu izuzetka. C/C++ koristi dvije takve sheme. Jedan od njih - šema obnove- odgovara takozvanim strukturnim, ili C-izuzecima. Druga šema - nema obnove- odgovara C++ izuzecima. U prvoj shemi, rukovatelj izuzetkom - blok catch - vraća kontrolu u neku tačku u bloku try. U drugoj šemi, kontrola se ne vraća u blok pokušaja.

Uz neke sintaksičke razlike šema obnove koristi se u VB/VBA jezicima.

Šema rukovanja izuzecima u C#

Jezik C# je naslijedio shemu izuzetaka jezika C++, praveći vlastita prilagođavanja. Pogledajmo bliže krug i počnimo sa sintaksom konstrukcije pokušaj-uhvati-konačno:

pokušaj (...) uhvatiti (T1 e1) (...) ... uhvatiti(Tk ek) (...) konačno (...)

Bilo gdje u tekstu modula gdje je blok sintaktički dozvoljen, blok se može učiniti zaštićenim dodavanjem ključne riječi try. Blok try može biti praćen blokovima catch pod nazivom blokovi za obradu izuzetaka, može ih biti nekoliko, a mogu i izostati. Završava ovaj niz konačno blokirati- blok finalizacije, koji takođe može nedostajati. Cijela ova struktura može biti ugniježđena - blok try može uključiti strukturu pokušaj-uhvati-konačno.

Dodavanje izuzetaka. Kreiranje objekata izuzetaka

U tijelu pokušajnog bloka može doći do toga izuzetna situacija, što dovodi do bacanje izuzetaka. Formalno bacanje izuzetka javlja se kada se izvrši naredba throw. Ovaj operator se najčešće izvršava u dubinama operativnog sistema, kada sistem komandi ili API funkcija ne može da radi svoj posao. Ali ovaj operater može biti dio tekst programa pokušati blokirati i izvršiti kada, kao rezultat analize, postane jasno da dalje normalan rad nemoguće.

Sintaktički, operator throw izgleda ovako:

baciti [izraz]

Izraz throw specificira objekat klase koji je potomak klase Exception. Obično je ovo novi izraz, koji stvara novi objekat. Ako nedostaje, trenutni izuzetak se vraća. Ako se izbaci izuzetak operativni sistem, onda sam klasifikuje izuzetak, kreira objekat odgovarajuće klase i automatski popunjava njegova polja.

U modelu koji razmatramo, izuzeci su objekti čija je klasa potomak klase Exception. Ova klasa i njeni brojni potomci su dio FCL biblioteke, iako su raštrkani po različitim imenskim prostorima. Svaka klasa specificira određeni tip izuzeci prema klasifikaciji usvojenoj u .Net Framework-u. Evo samo nekoliko klase izuzetaka iz System imenskog prostora: ArgumentException, ArgumentOutOfRangeException, ArithmeticException, BadImageFormatException, DivideByZeroException, OverflowException. Imenski prostor System.IO sadrži klase izuzetaka vezano za I/O probleme: DirectoryNotFoundException, FileNotFoundException i mnogi drugi. Svačija imena klase izuzetaka završiti riječju izuzetak. Dozvoljeno vam je da kreirate svoje klase izuzetaka, naslijeđujući ih od klase Exception.

Kada se izvede naredba throw, kreira se objekat te, čija TE klasa karakteriše trenutni izuzetak, a polja sadrže informacije o izuzetku koji se dogodio. izuzetna situacija. Izvršavanje naredbe throw uzrokuje zaustavljanje normalnog procesa izračunavanja. Ako se to dogodi u zaštićenom bloku pokušaja, tada počinje korak "hvatanje" izuzetka jedan od obrađivača izuzetaka.

Hvatanje izuzetka

Blok catch - obrađivač izuzetaka ima sljedeću sintaksu:

uhvatiti (T e) (...)

Klasa T specificirana u zaglavlju catch bloka mora pripadati klase izuzetaka. Blok catch sa formalnim argumentom e klase T ima potencijal da uhvati trenutni izuzetak te klase TE ako i samo ako je objekt te kompatibilan sa objektom e. Drugim riječima, potencijal hvatanja znači da je dodjela e = te važeća, što je moguće kada je klasa TE potomak klase T. Rukovalac čija je klasa T klasa izuzetaka je univerzalni rukovalac, potencijalno je u stanju uhvatiti bilo koji izuzetak jer su svi njegova djeca.

Potencijalnih osvajača može biti mnogo, samo je jedan isključen – onaj koji je prvi na listi za provjeru. Koja je procedura verifikacije? On je prilično prirodan. Rukovatelji se prvo provjeravaju redoslijedom kojim prate blok try, a prvi potencijalni hvatač postaje aktivan, hvata izuzetak i obrađuje ga. Iz ovoga postaje jasno da je redosled u listi blokova za hvatanje izuzetno važan. Većina dolazi prva specijalizovanih procesora, dalje kako se univerzalnost povećava. Dakle, prvo bi trebao postojati obrađivač izuzetaka DivideByZeroException, a zatim Main. Ako u njemu nema potencijalnog grabbera izuzetaka, tada će raditi standardni rukovalac, koji će prekinuti izvršavanje programa i izdati odgovarajuću poruku.

Dobar dan! Danas ćemo govoriti o tome kako postupati s greškama u programima napisanim na C#.

Želio bih odmah napomenuti da se greške u programima mogu podijeliti u dvije grupe: greške u vremenu sastavljanja programa (u fazi kompilacije) i greške u izvođenju programa. Ovaj vodič će govoriti o greškama u toku izvođenja!

Prisjetimo se primjera iz prethodne lekcije, gdje je korisnik morao da unese dva cijela broja sa tastature. Zatim sam također tražio da unesem brojeve i cijele brojeve. Zašto? Prije jer ako u taj program unesete ne broj, već samo tekst, ili ne cijeli, već razlomak, onda će doći do greške u izvođenju! Iz tog razloga vam danas govorim o mehanizmima i principima rukovanja greškama u programima.

I tako, ako sumnjamo da naš program može imati greške u izvođenju, na primjer, zbog činjenice da je korisnik unio pogrešne podatke, moramo se pobrinuti za rukovanje tim greškama. Pristup obradi slične situacije je slijedeći pravila: označen je blok koda čije izvršavanje može uzrokovati greške; dodjeljuje se blok koda koji je odgovoran za obradu grešaka koje su se dogodile.

Naznačen je blok koda u kojem se mogu pojaviti greške ključna riječ probaj praćeno proteze(koji potencijalno sadrže opasnim operacijama). Neposredno nakon takvog bloka trebao bi biti blok za obradu grešaka, koji se označava ključnom riječi uhvatiti, a u zagradama iza ove riječi, vrsta grešaka koje blok podataka obrađuje nakon zatvaranja zagrada, zatim kovrdžave, u okviru kojih se provodi obrada. Šematski, to izgleda ovako:

Pokušajte ( // Potencijalno opasan blok koda ) catch ( error_type ) ( // Rukovanje greškom ) // Dalji programski izrazi

I radi ovako ako je u bloku probaj, nije došlo do greške, a zatim blokirajte uhvatiti se ne izvršava, već se kontrola prenosi, tj. sljedeći blok se izvršava uhvatiti operater. Ali ako je unutar bloka probaj dođe do greške, izvršenje ovog bloka se prekida i kontrola se prenosi na blok uhvatiti, a tek tada se izvršavaju operatori koji slijede ovaj blok.

U praksi, nakon jednog bloka probaj, može biti nekoliko blokova uhvatiti, za odvojeno rukovanje greškama različitih tipova.

Izmijenimo programski kod iz prethodne lekcije, dodamo kontrolu i rukovanje greškama koje mogu nastati kada korisnik unese netačne podatke.

//Potencijalno opasan pokušaj blokiranja ( //Zatražite od korisnika da unese prvi broj Console.Write("Unesite prvi broj i pritisnite Enter ključ: "); //Dobijanje stringa prvog reda firstString = Console.ReadLine(); //Pretvaranje prvog retka u broj int firstArg = Convert.ToInt32(firstString); //Traženje od korisnika da unese drugi broj Console. Write("Unesite prvi broj i pritisnite tipku Enter: "); //Dobijanje niza drugog reda secondString = Console.ReadLine(); //Pretvaranje drugog retka u broj int secondArg = Convert.ToInt32(secondString); //Dodavanje dvije varijable int result = firstArg + secondArg ; //Izlaz rezultata Console.WriteLine("Rezultat zbrajanja unesenih brojeva: " + result.ToString()); ) //Blok rukovanja greškom, SystemException - najviše uobičajen tip hvatanja grešaka (SystemException) ( Console.WriteLine("Tokom izvođenja došlo je do greške programa, vjerovatno su uneseni netačni podaci!"); )

Sada, ako korisnik unese netačne podatke umjesto cijelog broja, greška koja se pojavi će biti obrađena. Ako zalijepite ovaj kod u " glavni", izgradite i pokrenite program, vidjet ćete sljedeće ponašanje:

I tako, u ovoj lekciji je to predstavljeno Osnovne informacije u vezi sa mehanizmom za rukovanje greškama (situacije izuzetaka) u C# jeziku. U sljedećoj lekciji ćemo govoriti o kreiranju i korištenju vlastitih metoda (funkcija), a više puta ćemo se vraćati na temu rukovanja greškama!

Najbolji članci na ovu temu