Kako postaviti pametne telefone i računala. Informativni portal
  • Dom
  • Savjet
  • Tipične pogreške u C kodu Sharp. Otklanjanje pogrešaka i rukovanje iznimkama

Tipične pogreške u C kodu Sharp. Otklanjanje pogrešaka i rukovanje iznimkama

Osnove rukovanja iznimkama

Pogreške nisu uvijek krivnja osobe koja kodira aplikaciju. Ponekad aplikacija generira pogrešku zbog radnji krajnjeg korisnika ili je pogreška uzrokovana kontekstom okruženja u kojem se kôd izvodi. U svakom slučaju, uvijek biste trebali očekivati ​​da će se pojaviti pogreške u vašim aplikacijama i kodirati u skladu s tim očekivanjima.

.NET Framework pruža napredno rukovanje pogreškama. C#-ov mehanizam za rukovanje pogreškama omogućuje vam kodiranje prilagođenog rukovanja za svaku vrstu stanja pogreške, kao i odvajanje koda koji potencijalno generira pogreške od koda koji ih obrađuje.

Što god uzrokovalo problem, aplikacija na kraju ne radi kako se očekuje. Prije nego što pogledamo rukovanje strukturiranim iznimkama, upoznajmo se s tri najčešće korištena izraza za opisivanje anomalija:

Softverske pogreške (bugovi)

Ovo je obično naziv za pogreške 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 pogreška.

Pogreške korisnika

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

Iznimke

Iznimke ili iznimne situacije obično se nazivaju anomalijama koje se mogu pojaviti tijekom izvođenja i koje je teško, ako ne i nemoguće, predvidjeti prilikom programiranja aplikacije. Moguće iznimke uključuju pokušaje povezivanja s bazom podataka koja više ne postoji, pokušaje otvaranja oštećena datoteka ili pokušaj uspostavljanja komunikacije sa strojem koji je trenutno u izvanmrežni način rada. U svakom od ovih slučajeva, programer (i krajnji korisnik) može malo učiniti u vezi s takvim "iznimnim" okolnostima.

Iz gornjih opisa bi trebalo biti jasno da strukturirano rukovanje iznimkama u .NET je tehnika dizajnirana za rukovanje iznimkama koje se mogu pojaviti tijekom izvođenja. Međutim, čak i u slučaju softverskih i korisničkih pogrešaka koje izmiču oku programera, CLR će često automatski izbaciti odgovarajuću iznimku s opisom trenutni problem. Postoje mnoge različite iznimke definirane u bibliotekama osnovnih klasa .NET, kao što su FormatException, IndexOutOfRangeException, FileNotFoundException, ArgumentOutOfRangeException, itd.

U .NET terminologiji, "iznimka" se odnosi na softverske pogreške, korisničke pogreške i pogreške tijekom izvođenja. Prije nego što uđemo u detalje, pogledajmo ulogu strukturiranog rukovanja iznimkama i kako se ono razlikuje od tradicionalnih tehnika rukovanja pogreškama.

Uloga rukovanja iznimkama u .NET-u

Prije .NET-a, rukovanje greškama u radnom okruženju Windows sustavi bila vrlo zbunjujuća mješavina tehnologija. Mnogi programeri uključili su vlastitu logiku rukovanja pogreškama u kontekstu aplikacije od interesa. Na primjer, razvojni tim može definirati skup numeričkih konstanti za predstavljanje poznatih situacija kvarova i zatim koristiti te konstante kao povratne vrijednosti metode.

Uz tehnike koje su izmislili sami programeri, Windows API definira stotine kodova pogrešaka pomoću #define i HRESULT, kao i mnoge varijacije jednostavnih Booleovih vrijednosti (bool, BOOL, VARIANT BOOL, itd.). Štoviše, mnogi programeri COM aplikacija u C++ (i također VB 6) eksplicitno ili implicitno koriste mali skup standardnih COM sučelja (poput ISupportErrorInfo.IErrorInfo ili ICreateErrorInfo) za vraćanje razumljivih informacija o pogrešci COM klijentu.

Očigledni problem svih ovih starijih tehnika je nedostatak simetrije. Svaki od njih više-manje se uklapa u okvir jedne tehnologije, jednog jezika, a možda čak i jednog projekta. .NET podržava standardnu ​​tehniku ​​za generiranje i otkrivanje pogrešaka tijekom izvođenja tzv rukovanje strukturiranom iznimkom (SEH) .

Ljepota ove tehnike je u tome što omogućuje programerima korištenje jedinstvenog pristupa rukovanju pogreškama koji je zajednički svim jezicima koji se temelje na .NET-u. Zbog toga C# programer može rješavati pogreške na gotovo isti sintaktički način kao VB programer i C++ programer koji koristi C++/CLI.

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

Zadnja izmjena: 23.10.2018

Ponekad se prilikom izvođenja programa dogode greške koje je teško predvidjeti ili anticipirati, a ponekad i nemoguće. Na primjer, prilikom prijenosa datoteke preko mreže, mrežna veza može neočekivano prekinuti. takve situacije se nazivaju izuzecima. Jezik C# pruža programerima mogućnosti za rješavanje takvih situacija. Konstrukcija try...catch...finally u C# je dizajnirana za to.

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

Kada koristite blok try...catch..finally, sve naredbe u bloku try se prvo izvršavaju. Ako se u ovom bloku ne pojave iznimke, tada se nakon njegovog izvođenja počinje izvršavati finally blok. I onda try..catch..konačno završi svoj posao.

Ako se iznenada dogodi iznimka u bloku pokušaja, normalni redoslijed izvršenja se zaustavlja i CLR počinje tražiti blok za hvatanje koji može obraditi ova iznimka. Ako potreban blok catch je pronađen, zatim se izvršava, a nakon što završi, finally blok se izvršava.

Ako se traženi catch blok ne pronađe, tada kada se dogodi iznimka, program neuobičajeno prekida svoje izvođenje.

Razmotrite sljedeći primjer:

Klasa Program ( static void Main(string args) ( int x = 5; int y = x / 0; Console.WriteLine($"Rezultat: (y)"); Console.WriteLine("Kraj programa"); ​​Console.Read () )

U u ovom slučaju broj se dijeli s 0, što će generirati iznimku. A kada pokrenemo aplikaciju u načinu rada za otklanjanje pogrešaka, vidjet ćemo in Vizualni studio prozor koji obavještava o iznimci:

U ovom prozoru vidimo da se dogodila iznimka koja je tipa System.DivideByZeroException, odnosno pokušaj dijeljenja s nulom. Pomoću stavke Pregled pojedinosti možete vidjeti više detaljne informacije o iznimci.

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

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

Program klase ( static void Main(string args) ( try ( int x = 5; int y = x / 0; Console.WriteLine($"Rezultat: (y)"); ) catch ( Console.WriteLine("Dogodila se iznimka ! "); ) konačno ( Console.WriteLine("Konačni blok"); ) Console.WriteLine("Kraj programa"); ​​Console.Read(); ) )

U ovom slučaju, opet ćemo imati iznimku u bloku try, jer pokušavamo podijeliti s nulom. I dostizanje crte

Int y = x / 0;

izvođenje programa će se zaustaviti. CLR će pronaći catch blok i prenijeti kontrolu na taj blok.

Nakon catch bloka, finally blok će se izvršiti.

Dogodila se iznimka! konačno blok Kraj programa

Dakle, program i dalje neće izvoditi dijeljenje s nulom i stoga neće ispisati rezultat ovog dijeljenja, ali sada se neće srušiti, a iznimka će se obraditi u bloku catch.

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

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

Obrnuto, ako imamo finally blok, možemo izostaviti catch blok i ne obraditi iznimku:

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

Međutim, iako je takva konstrukcija sasvim ispravna sa stajališta C# sintakse, unatoč tome, budući da CLR ne može pronaći traženi catch blok, iznimka se neće obraditi i program će se srušiti.

Rukovanje iznimkama i uvjeti

Red iznimne situacije može predvidjeti investitor. 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 ne unese broj, već niz ili neke druge znakove, program će izbaciti pogrešku. S jedne strane, upravo je to situacija kada možete koristiti blok try..catch za obradu moguća greška. Međutim, bilo bi puno optimalnije provjeriti valjanost pretvorbe:

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("Kvadratni broj: " + 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 valjana, varijabla x će sadržavati uneseni broj. Dakle, bez korištenja try...catch, možete riješiti moguću iznimku.

Sa stajališta performansi, korištenje try..catch blokova je skuplje od korištenja uvjeta. Stoga, ako je moguće, umjesto try..catch bolje je koristiti kondicionali provjeriti iznimke.

konstante uvjetne kompilacije. Omogućuje definiranje konstanti 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 mijenjanja projektnog koda ili potrebe da se ponovno kompajlira.

Visual Studio .Net Debugging i Workbench

Programeru najviše pruža instrumentalno okruženje studija širok raspon mogućnosti praćenja napredovanja izračuna i praćenja stanja u kojima se proces izračuna nalazi. Jer svi su moderni instrumentalna okruženja su organizirani na sličan način i dobro su poznati programerima koji rade, dopustit ću si da se ne zadržavam na opisu mogućnosti okruženja.

Rukovanje iznimkama

Koji god pouzdan kod bez obzira na to koliko je temeljito napisana, bez obzira na to koliko je temeljito otklanjanje pogrešaka, verzija prenesena na rad i održavanje naići će na kršenja specifikacija tijekom pokretanja. Razlog tome su gore navedeni zakoni softverski inženjeri. Ostaje u sustavu zadnja greška, postoje korisnici koji ne znaju specifikacije, a ako se specifikacija može prekršiti, onda će se ovaj događaj jednog dana dogoditi. Takav iznimne situacije nastavak izvođenja programa ili ono postaje nemoguće (pokušaj neovlaštene operacije dijeljenja s nulom, pokušaji upisivanja u zaštićeno područje memorije, pokušaj otvaranja nepostojeća datoteka, pokušaj dobivanja nepostojećeg zapisa baze podataka), ili će u nastaloj situaciji korištenje algoritma dovesti do pogrešnih rezultata.

Što učiniti ako se to dogodi iznimna situacija? Naravno uvijek ima standardni način- prijaviti grešku i prekinuti izvođenje programa. Jasno je da je to prihvatljivo samo za bezopasne primjene; čak za računalne igrice Ova metoda nije prikladna, a kamoli za kritične aplikacije!

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

Rukovanje iznimkama u jezicima C/C++

C stil programiranja karakterizira opisivanje metoda klasa kao Booleove funkcije, vraćajući true ako metoda završi normalno i false ako se dogodi iznimna situacija. Poziv metode ugrađen je u naredbu If koja obrađuje pogrešku ako metoda ne uspije završiti:

bool MyMethod(...)(...) if !MyMethod())(// obrada grešaka) (//normalno izvođenje)

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

Stoga C/C++ koristi shemu blokova try/catch, čija je bit sljedeća. Odjeljak programa u kojem se može pojaviti iznimna situacija, formatiran je kao zaštićeni pokušajni blok. Ako prilikom izvođenja postoji iznimna situacija, tada se izvođenje bloka pokušaja s klasifikacijom izuzetaka prekida. Ovu iznimku počinje obrađivati ​​jedan od catch blokova koji odgovaraju vrsti iznimke. C/C++ koristi dvije takve sheme. Jedan od njih - shema obnove- odgovara takozvanim strukturnim ili C-iznimkama. Druga shema - bez obnove- odgovara C++ iznimkama. U prvoj shemi, rukovatelj iznimkama - blok catch - vraća kontrolu na neku točku u bloku pokušaja. U drugoj shemi kontrola se ne vraća u blok pokušaja.

Uz neke sintaktičke razlike shema obnove koristi se u VB/VBA jezicima.

Shema rukovanja iznimkama u C#

Jezik C# naslijedio je shemu izuzetaka jezika C++, napravivši joj vlastite prilagodbe. Pogledajmo pobliže krug i započnimo sa sintaksom konstrukcije pokušaj-uhvati-konačno:

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

Bilo gdje u tekstu modula gdje je blok sintaktički dopušten, blok se može učiniti zaštićenim dodavanjem ključne riječi try. Nakon bloka try mogu uslijediti pozvani blokovi catch blokovi rukovatelja iznimkama, može ih biti nekoliko ili ih možda nema. Dovršava ovaj niz konačno blokirati- blok finalizacije, koji također može nedostajati. Cijela ova konstrukcija može biti ugniježđena - blok try može uključivati ​​konstrukciju pokušaj-uhvati-konačno.

Bacanje iznimaka. Stvaranje objekata iznimke

Može se pojaviti u tijelu try bloka iznimna situacija, dovodi do bacanje iznimaka. Formalno bacanje iznimke događa se kada se izvrši naredba throw. Ovaj se operator najčešće izvršava u dubini operacijskog sustava, kada sustav naredbi ili API funkcija ne može raditi svoj posao. Ali ovaj operater može biti dio tekst programa pokušajte blokirati i izvršiti kada, kao rezultat analize, postane jasno da dalje normalna operacija nemoguće.

Sintaktički, operator bacanja izgleda ovako:

bacanje [izraz]

Izraz throw specificira objekt klase koja je potomak klase Exception. Obično je to novi izraz koji stvara novi objekt. Ako nedostaje, trenutna iznimka se ponovno baca. Ako se izbaci izuzetak operacijski sustav, zatim sam klasificira iznimku, kreira objekt odgovarajuće klase i automatski popunjava njegova polja.

U modelu koji razmatramo iznimke su objekti čija je klasa potomak klase Exception. Ova klasa i njezini brojni potomci dio su FCL biblioteke, iako su razbacani po različitim imenskim prostorima. Svaka klasa specificira određena vrsta iznimke prema klasifikaciji usvojenoj u .Net Frameworku. Evo samo nekoliko klase izuzetaka iz imenskog prostora sustava: ArgumentException, ArgumentOutOfRangeException, ArithmeticException, BadImageFormatException, DivideByZeroException, OverflowException. Imenski prostor System.IO sadrži klase izuzetaka vezane uz I/O probleme: DirectoryNotFoundException, FileNotFoundException i mnogi drugi. Svačija imena klase izuzetaka završavaju riječju Iznimka . Dopušteno vam je kreirati vlastito klase izuzetaka, nasljeđujući ih od klase Exception.

Kada se izvrši naredba throw, kreira se objekt te, čija klasa TE karakterizira trenutnu iznimku, a polja sadrže informacije o iznimci koja se dogodila. iznimna situacija. Izvršenje naredbe throw uzrokuje zaustavljanje normalnog procesa izračunavanja. Ako se to dogodi u čuvanom bloku pokušaja, tada počinje korak "hvatanje" iznimke jedan od rukovatelja iznimkama.

Hvatanje iznimke

Blok catch - rukovatelj iznimkama ima sljedeću sintaksu:

uhvatiti (T e) (...)

Klasa T navedena u zaglavlju catch bloka mora pripadati klase izuzetaka. Blok catch s formalnim argumentom e klase T ima potencijal uhvatiti trenutnu iznimku te klase TE ako i samo ako je objekt te dodjela kompatibilna s 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. Rukovatelj čija je klasa T klasa iznimke je univerzalni rukovatelj, potencijalno je u stanju uhvatiti bilo koju iznimku budući da su svi oni njegova djeca.

Mogućih napadača može biti mnogo; samo jedan je isključen - onaj koji je prvi na popisu za provjeru. Kakav je postupak verifikacije? Prilično je prirodan. Rukovatelji se prvo provjeravaju redoslijedom kojim slijede blok pokušaja, a prvi potencijalni hvatač postaje aktivan, hvata iznimku i rukuje njome. Iz ovoga postaje jasno da je redoslijed u popisu catch blokova izuzetno važan. Većina je na prvom mjestu specijalizirani procesori, dalje kako se univerzalnost povećava. Dakle, prvo bi trebao postojati DivideByZeroException rukovatelj iznimkama, a zatim Main. Ako u njemu nema potencijalnog hvatača izuzetaka, tada će standardni rukovatelj raditi, prekidajući izvođenje programa i izdajući odgovarajuću poruku.

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

Želio bih odmah napomenuti da se pogreške u programima mogu podijeliti u dvije skupine: pogreške prilikom sastavljanja programa (u fazi kompilacije) i pogreške tijekom izvođenja programa. Ovaj vodič će govoriti o pogreškama prilikom izvođenja!

Sjetimo se primjera iz prethodne lekcije, gdje je korisnik s tipkovnice morao unijeti dva cijela broja. Zatim sam također tražio unos brojeva i cijelih brojeva. Zašto? Prije, jer ako u taj program unesete ne broj, već samo tekst, ili ne cijeli broj, već razlomak, tada će doći do pogreške prilikom izvođenja! Iz tog razloga vam danas govorim o mehanizmima i principima obrade grešaka u programima.

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

Naveden je blok koda u kojem se mogu pojaviti pogreške ključna riječ probati slijedi naramenice(koje potencijalno sadrže opasne operacije). Odmah nakon takvog bloka trebao bi postojati blok za obradu grešaka; on je označen ključnom riječi ulov, a u zagradama iza ove riječi vrsta pogrešaka koje podatkovni blok koda obrađuje nakon zatvaranja zagrada, zatim kovrčavi unutar kojih se provodi obrada. Shematski to izgleda ovako:

Try ( // Potencijalno opasan blok koda ) catch ( error_type ) ( // Rješavanje pogrešaka ) // Daljnje izjave programa

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

U praksi, nakon jednog bloka probati, može biti nekoliko blokova ulov, za odvojeno rukovanje pogreškama različitih vrsta.

Modificirajmo programski kod iz prethodne lekcije, dodamo kontrolu i obradu grešaka koje se mogu pojaviti kada korisnik unese netočne podatke.

//Potencijalno opasan pokušaj blokiranja ( //Tražite od korisnika da unese prvi broj Console.Write("Unesite prvi broj i pritisnite Enter tipka: "); //Dohvaćanje niza prvog retka 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: "); //Dohvaćanje niza drugog retka secondString = Console.ReadLine(); //Pretvaranje drugog retka u broj int secondArg = Convert.ToInt32(secondString); //Dodavanje dviju varijabli int result = firstArg + secondArg ; //Izlaz rezultata Console.WriteLine("Rezultat zbrajanja unesenih brojeva: " + result.ToString()); //Blok obrade pogreške, SystemException - najčešći type of errors catch (SystemException) ( Console.WriteLine("Tijekom izvođenja) došlo je do greške u programu, vjerojatno su uneseni netočni podaci!");

Sada, ako korisnik unese netočan podatak umjesto cijelog broja, pogreška koja se pojavi bit će obrađena. Ako zalijepite ovaj kod u " Glavni", izradite i pokrenite program, vidjet ćete sljedeće ponašanje:

I tako, u ovoj lekciji je predstavljeno Osnovne informacije koji se tiču ​​mehanizma za obradu grešaka (iznimne situacije) u jeziku C#. U sljedećoj lekciji govorit ćemo o stvaranju i korištenju vlastitih metoda (funkcija), te ćemo se više puta vratiti na temu obrade grešaka!

Najbolji članci na temu