C# vyvoláva výnimku. Ladenie a spracovanie výnimiek

  • 17.04.2019

Posledná aktualizácia: 23.10.2018

Niekedy sa pri vykonávaní programu vyskytnú chyby, ktoré je ťažké predvídať alebo predvídať a niekedy dokonca nemožné. Napríklad pri prenose súboru cez sieť môže neočakávane prepadnúť sieťové pripojenie. takéto situácie sa nazývajú výnimky. Jazyk C# poskytuje vývojárom možnosti na zvládnutie týchto situácií. Konštrukt try...catch...finally je na to určený v C#.

Skúste ( ) chytiť ( ) nakoniec ( )

Pri použití bloku try...catch..finally sa najskôr vykonajú všetky príkazy v bloku try. Ak sa v tomto bloku nevyskytli žiadne výnimky, potom po jeho vykonaní, konečne zablokovať. A potom pokus..chyt..konštrukt dokončí svoju prácu.

Ak sa v bloku try vyskytne výnimka, potom obyčajná objednávka vykonávanie sa zastaví a CLR začne hľadať blok catch, ktorý dokáže spracovať danú výnimku. Ak požadovaný blok catch sa nájde, potom sa vykoná a po jeho dokončení sa vykoná posledný blok.

Ak sa požadovaný blok úlovku nenájde, program pri výskyte výnimky spadne.

Zvážte nasledujúci príklad:

Class Program ( static void Main(string args) ( int x = 5; int y = x / 0; Console.WriteLine($"Výsledok: (y)"); Console.WriteLine("Koniec programu"); Console.Prečítajte si (); ) )

AT tento prípadčíslo sa vydelí 0, čo vyvolá výnimku. A pri spustení aplikácie v režime ladenia uvidíme v vizuálne štúdio okno, ktoré informuje o výnimke:

V tomto okne vidíme, že nastala výnimka, ktorá predstavuje typ System.DivideByZeroException , teda pokus o delenie nulou. Pomocou položky Zobraziť podrobnosti môžete vidieť viac detailné informácie o výnimke.

A v tomto prípade nám ostáva už len ukončiť vykonávanie programu.

Aby ste sa vyhli takémuto zlyhaniu programu, mali by ste použiť konštrukciu try...catch...finally na spracovanie výnimiek. Takže prepíšme príklad takto:

Class Program ( static void Main(string args) ( try ( int x = 5; int y = x / 0; Console.WriteLine($"Result: (y)"); ) catch ( Console.WriteLine("Vyskytla sa výnimka ! "); ) nakoniec ( Console.WriteLine("Konečne zablokovať"); ) Console.WriteLine("Koniec programu"); ​​Console.Read(); ) )

V tomto prípade budeme mať opäť výnimku v bloku try, keďže sa snažíme deliť nulou. A dosiahnuť čiaru

Int y = x/0;

vykonávanie programu sa zastaví. CLR nájde blok catch a odovzdá riadenie tomuto bloku.

Po bloku catch sa vykoná posledný blok.

Nastala výnimka! nakoniec blok Koniec programu

Program teda stále nevykoná delenie nulou, a preto nevytlačí výsledok tohto delenia, ale teraz sa nezrúti a výnimka bude spracovaná v bloku catch.

Treba poznamenať, že v tomto konštrukte sa vyžaduje blok try. S blokom catch môžeme vynechať blok konečne:

Skúste ( int x = 5; int y = x / 0; Console.WriteLine($"Result: (y)"); ) catch ( Console.WriteLine("Vyskytla sa výnimka!"); )

Naopak, ak existuje blok konečne, môžeme blok catch vynechať a výnimku nespracovať:

Skúste ( int x = 5; int y = x / 0; Console.WriteLine($"Výsledok: (y)"); ) nakoniec ( Console.WriteLine("Konečne blokovať"); )

Aj keď je syntax jazyka C# správna, keďže CLR nemôže nájsť správny blok catch, výnimka nebude spracovaná a program spadne.

Spracovanie výnimiek a podmienené konštrukcie

riadok výnimočné situácie môže predvídať vývojár. Povedzme napríklad, že program zabezpečuje zadanie čísla a výstup jeho štvorca:

Static void Main(string args) ( Console.WriteLine("Zadajte číslo"); int x = Int32.Parse(Console.ReadLine()); x *= x; Console.WriteLine("Číselný štvorec: " + x) ; Console.Read(); )

Ak používateľ nezadá číslo, ale reťazec, niektoré ďalšie znaky, program spadne do chyby. Na jednej strane je to presne tá situácia, kedy môžete použiť blok try..catch na spracovanie možná chyba. Oveľa optimálnejšie by však bolo skontrolovať platnosť konverzie:

Static void Main(string args) ( Console.WriteLine("Zadajte číslo"); int x; string input = Console.ReadLine(); if (Int32.TryParse(input, out x)) ( x *= x; Console . WriteLine("Číslo na druhú: " + x); ) else ( Console.WriteLine("Nesprávny vstup"); ) Console.Read(); )

Metóda Int32.TryParse() vráti hodnotu true, ak je konverzia možná, a hodnotu false, ak nie. Ak je prevod povolený, x bude obsahovať zadané číslo. Takže bez použitia try...catch zvládnete prípadnú výnimku.

Z hľadiska výkonu je používanie blokov try..catch drahšie ako používanie podmienených konštruktov. Preto, ak je to možné, namiesto try..catch je lepšie použiť podmienené konštrukty na kontrolu výnimočných situácií.

Chytanie výnimiek

Berúc do úvahy to. Internetová sieť zahŕňa veľké množstvo preddefinovaných tried výnimiek, vzniká otázka: ako ich použiť v kóde na zachytenie chybných podmienok? Aby bolo možné riešiť možné chybné situácie v kóde C#, program je zvyčajne rozdelený do blokov po troch odlišné typy:

    Bloky skúste zapuzdrený kód, ktorý tvorí súčasť bežných akcií programu, ktorý by mohol potenciálne naraziť na vážne chybové situácie.

    Bloky chytiť zapuzdrený kód, ktorý spracováva chybné situácie, vyskytujúce sa v kóde bloku try. je to rovnaké pohodlné miesto pre protokolovanie chýb.

    Bloky konečne zapuzdrený kód, ktorý vyčistí všetky zdroje alebo vykoná iné akcie, ktoré by sa za normálnych okolností vykonali na konci bloku try alebo catch. Je dôležité pochopiť, že tento blok sa vykoná bez ohľadu na to, či je vyvolaná výnimka alebo nie.

skúsiť a chytiť

Jadrom spracovania výnimiek v C# je pár Kľúčové slová skúsiť a chytiť. Tieto kľúčové slová fungujú spoločne a nemožno ich použiť samostatne. Nasleduje všeobecná forma definovania blokov try/catch na spracovanie výnimiek:

try ( // Blok kódu skontrolovaný na chyby. ) catch (ExcepType1 exOb) ( // Obslužný nástroj výnimky typu ExcepType1. ) catch (ExcepType2 exOb) ( // Obslužný nástroj výnimky typu ExcepType2. ) ...

kde ExcepType je typ vyvolanej výnimky. Keď je výnimka vyvolaná príkazom try, je zachytená jeho párovým príkazom catch, ktorý potom spracuje výnimku. V závislosti od typu výnimky sa vykoná aj príslušný príkaz catch. Takže, ak sú typy vyvolanej výnimky a to, čo je špecifikované v príkaze catch rovnaké, potom sa vykoná tento konkrétny príkaz a všetky ostatné sa preskočia. Keď je zachytená výnimka, premenná výnimky exOb získa svoju hodnotu. V skutočnosti nie je potrebné špecifikovať premennú exOb. Napríklad nie je potrebné špecifikovať, ak obsluha výnimky nepotrebuje prístup k objektu výnimky, čo sa často stáva. Na spracovanie výnimky stačí jej typ.

Všimnite si však, že ak nie je vyvolaná žiadna výnimka, blok príkazov try sa ukončí normálne a všetky jeho príkazy catch sa preskočia. Vykonávanie programu sa obnoví po prvom príkaze nasledujúcom po ukončujúcom príkaze catch. Príkaz catch sa teda vykoná len vtedy, ak je vyvolaná výnimka.

Pozrime sa na príklad, v ktorom sa budeme zaoberať výnimkou, ktorá nastane, keď je číslo delené 0:

Používanie systému; pomocou System.Collections.Generic; pomocou System.Linq; pomocou System.Text; menný priestor ConsoleApplication1 ( class Program ( static int MyDel(int x, int y) ( return x / y; ) static void Main() ( try ( Console.Write("Enter x: "); int x = int.Parse(Console) .ReadLine()); Console.Write("Zadajte y: "); int y = int.Parse(Console.ReadLine()); int vysledok = MyDel(x, y); Console.WriteLine("Vysledok: " + vysledok); ) // Spracovanie výnimky, ktorá sa vyskytuje pri delení nulovým úlovkom (DivideByZeroException) ( Console.WriteLine("Zistené delenie 0!!!\n"); Main(); ) // Spracovanie výnimky pri čísle je nesprávne zadané do úlovku konzoly (FormatException) ( Console.WriteLine("Toto NIE JE číslo!!!\n"); Main(); ) Console.ReadLine(); ) ) )

Tento jednoduchý príklad názorne ilustruje spracovanie výnimky pri delení 0 (DivideByZeroException), ako aj chybu používateľa pri zadávaní nečísla (FormatException).

Dôsledky nechytania výnimiek

Zachytenie jednej zo štandardných výnimiek, ako v príklade vyššie, má ďalšiu výhodu: zabraňuje zlyhaniu programu. Akonáhle je vyvolaná výnimka, musí byť zachytená nejakým kúskom kódu na určitom mieste v programe. Vo všeobecnosti, ak výnimku nezachytí program, zachytí ju runtime systém. Faktom však je, že vykonávajúci systém vydá chybové hlásenie a preruší vykonávanie programu.

Dobrý deň! Dnes si povieme, ako riešiť chyby v programoch napísaných v C#.

Chcel by som hneď poznamenať, že chyby v programoch možno podmienečne rozdeliť do dvoch skupín: chyby pri zostavovaní programu (vo fáze kompilácie) a chyby pri behu programu. V tomto návode budeme hovoriť o chybách pri spustení!

Spomeňme si na príklad z predchádzajúcej lekcie, kde mal používateľ zadať z klávesnice dve celé čísla. Potom som ešte žiadal zadať presne čísla a presne celé čísla. prečo? Pretože ak do tohto programu zadáte nie číslo, ale jednoducho text, alebo nie celé číslo, ale zlomkové číslo, potom sa vyskytne chyba pri spustení! Z tohto dôvodu vám dnes hovorím o mechanizmoch a princípoch spracovania chýb v programoch.

A tak, ak máme podozrenie, že náš program môže mať chyby pri behu, napríklad v dôsledku toho, že používateľ zadal nesprávne údaje, musíme sa postarať o riešenie týchto chýb. Prístup k riešeniu takýchto situácií spočíva v nasledujúcich pravidlách: pridelí sa blok kódu, pri vykonávaní ktorého môžu nastať chyby; je pridelený blok kódu, ktorý je zodpovedný za spracovanie chýb, ktoré sa vyskytli.

Blok kódu, v ktorom sa môžu vyskytnúť chyby, je označený kľúčovým slovom skúste nasledovaný rovnátka(ktoré obsahujú potenciálne nebezpečné operácie). Za takýmto blokom musí bezprostredne nasledovať blok spracovania chýb, ktorý je označený kľúčovým slovom chytiť a v zátvorkách za týmto slovom typ chýb, ktoré blok kódu spracováva po uzavretí zátvorka, nasledujú kučeravé, v rámci ktorých je implementované spracovanie. Schematicky to vyzerá takto:

Skúste ( //Potenciálne nebezpečný blok kódu )catch(error_type) ( //Spracovanie chýb ) //Ďalšie príkazy programu

A funguje to takto, ak v bloku skúste, nenastala žiadna chyba, potom blok chytiť sa nevykoná a kontrola sa prenáša ďalej, t.j. vykonávané po bloku chytiť operátor. Ale ak vo vnútri bloku skúste dôjde k chybe, vykonávanie tohto bloku sa preruší a riadenie sa prenesie na blok chytiť a až potom sa vykonajú príkazy nasledujúce po tomto bloku.

V praxi po jednom bloku skúste, môže existovať niekoľko blokov chytiť na samostatné spracovanie rôznych typov chýb.

Upravme programový kód z predchádzajúcej lekcie, pridáme kontrolu a obsluhu chýb, ktoré môžu nastať, keď používateľ zadá nesprávne údaje.

//Potenciálne nebezpečný pokus blokovať ( //Vyzvite používateľa, aby zadal prvé číslo Console.Write("Zadajte prvé číslo a stlačte Vstupný kľúč: "); //Získajte reťazec prvého reťazca firstString = Console.ReadLine(); //Konvertujte prvý reťazec na číslo int firstArg = Convert.ToInt32(firstString); //Výzva používateľa na zadanie druhého čísla Console. Write("Zadajte prvé číslo a stlačte Enter: "); //Získajte reťazec druhého reťazca secondString = Console.ReadLine(); //Preveďte druhý reťazec na číslo int secondArg = Convert.ToInt32(secondString); // Pridajte dve premenné int result = firstArg + secondArg ; //Výstup výsledku Console.WriteLine("Výsledok sčítania zadaných čísel: " + result.ToString()); ) //Blok spracovania chýb, SystemException - najviac všeobecný typ catch errors (SystemException) ( Console.WriteLine("Pri vykonávaní programu sa vyskytla chyba, pravdepodobne boli zadané nesprávne údaje!"); )

Teraz, ak používateľ zadá nesprávne údaje namiesto celého čísla, chyba, ktorá sa vyskytla, bude spracovaná. Ak tento kód vložíte do " hlavné", zostavte a spustite program, uvidíte nasledujúce správanie:

A tak v tejto lekcii boli prezentované základné informácie o mechanizme spracovania chýb (výnimočných situácií) v jazyku C#. V ďalšej lekcii si povieme o vytváraní a používaní vlastných metód (funkcií) a k téme odstraňovania chýb sa ešte viackrát vrátime!

Výnimkou je inštancia triedy, ktorá bola explicitne a implicitne zdedená zo základnej triedy System.Exception.

Premenné deklarované v bloku try vypadnú z rozsahu, keď sa riadenie odovzdá catch alebo nakoniec bloku. Na konci bloku try, aj keď sa nič nestalo (nenastala chyba), sa riadenie automaticky prenesie do bloku final, ktorý by mal obsahovať inštrukcie na uvoľnenie zdrojov.

Keď sa vyskytne chyba, kód vyvolá výnimku (vytvorí inštanciu triedy výnimky) a vyvolá ju takto:

Throw new IndexOutOfRangeException("Zadali ste: " + userInput);

Hneď ako kompilátor narazí príkaz hodiť vo vnútri bloku try okamžite hľadá zodpovedajúci blok catch.

Príkazy Throw nemusia byť v rovnakej metóde ako blok try, blok try pokračuje v činnosti, aj keď je riadenie odovzdané iným metódam.

Príkaz throw môže byť v akejkoľvek metóde volanej počas vykonávania bloku try - nemusí to byť v rovnakej metóde, v ktorej je definovaný blok try.

Obslužné nástroje výnimiek pre odvodenú triedu (IndexOutOfRangeException) musia predchádzať obslužné nástroje pre základnú triedu (Exception) (!)

Ak je handler catch napísaný ako: catch ( ... ), potom to znamená, že je zodpovedný za akýkoľvek kód (za akúkoľvek výnimku, ktorá sa vyskytne), vrátane tých, ktoré nie sú napísané v C# alebo nie sú spravované.

To, že len inštancie triedy odvodenej od System.Exception môžu byť odovzdané ako výnimky, je požiadavka C#.

Kým (pravda) // nekonečný kolobeh( Console.Write("Vyberte položku ponuky od 0 do 5 alebo ukončite: "); reťazec userInput = Console.ReadLine(); if (userInput == "") (Console.WriteLine("Klikli ste na ukončenie.. . "); break; ) try ( int x = int.Parse(userInput); switch (x) ( prípad 0: Console.WriteLine("Položka 0 je vybratá"); prestávka; prípad 1: Console.WriteLine("Položka 1 je vybratá "); prerušenie; prípad 2: Console.WriteLine("Vybratá položka 2"); prerušenie; prípad 3: Console.WriteLine("Vybratá položka 3"); prerušenie; prípad 4: Console.WriteLine("Položka 4" vybraté") ; prerušenie; prípad 5: Console.WriteLine("Vybratá položka 5"); prerušenie; predvolená hodnota: hodiť novú IndexOutOfRangeException(); break; ) ) catch (IndexOutOfRangeException e) ( Console.WriteLine("Neplatná hodnota. Vyberte číslica z ") ; ) catch (FormatException e) ( Console.WriteLine("Chyba prevodu, možno ste zadali reťazec..."); ) catch (Exception e) ( Console.WriteLine("Iná chyba"); ) catch () // handler pre nespravovaný kód a kód v inom jazyku )

Vlastnosti a metódy systému.Výnimka

if (ErrorCondition == true) (Výnimka myException = new ClassMyException("Pomoc!"); myException.Source = "Application Name"; myException.HelpLink = "myHelpFile.txt"; throw myException; )

Kód nemusí vyvolávať výnimky z všeobecná trieda System.Exception - nedáva žiadnu predstavu o povahe chybového stavu (!). V hierarchii sú dve dôležité triedy:

SystemException – Navrhnuté pre výnimky, ktoré zvyčajne vyvoláva .NET runtime, alebo výnimky všeobecnej povahy a môže ich vyvolať takmer každá aplikácia. Podtrieda predstavuje fatálne aj nefatálne chyby.

ApplicationException - je základ určený pre akúkoľvek triedu výnimiek definovaných tretími stranami.

IOException (namespace System.IO) sú spojené s čítaním a zápisom údajov do súboru.

Výnimka StackOverflowException nastane, keď je priestor zásobníka zaplnený do posledného miesta. Pretečenie zásobníka môže nastať napríklad vtedy, keď metóda začne rekurzívne volať samu seba. Bežnou príčinou EndOfStreamException je pokus o čítanie za hranicami súboru. Výnimka OverflowException je vyvolaná napríklad pri pokuse o pretypovanie int obsahujúceho -40 na uint v kontrolovanom kontexte.

Vnorené pokusy sa používajú z dvoch dôvodov:

- za účelom zmeny typu vygenerovanej výnimky (pomocou vlastnosti InnerException, ktorá obsahuje odkaz na akúkoľvek vygenerovanú výnimku);

- spracovanie rôznych výnimiek v rôznych častiach kódu.

Definovanie vlastných tried výnimiek

Definovanie vlastných výnimiek je pekné jednoduchá úloha, pretože zriedka k nim potrebujete pridať svoje vlastné metódy. Konštruktor je potrebné implementovať len preto, aby sa zabezpečilo správne volanie konštruktora základnej triedy.

Trieda LandLineSpyFoundException: ApplicationException ( public LandLineSpyFoundException(string spyName) : base("spy"+spyName) ( ) public LandLineSpyFoundException(reťazec spyName, Exception innerException) : base(spyName, innerException) ( ) )

Základy manipulácie s výnimkami

Chyby nie sú vždy vinou osoby, ktorá aplikáciu kóduje. Niekedy aplikácia generuje chybu v dôsledku akcií koncového používateľa alebo je chyba spôsobená kontextom prostredia, v ktorom je kód spustený. V každom prípade by ste mali vždy očakávať, že sa vo vašich aplikáciách a kóde vyskytnú chyby podľa týchto očakávaní.

.NET Framework poskytuje pokročilý systém spracovania chýb. Mechanizmus spracovania chýb C# vám umožňuje kódovať vlastné spracovanie pre každý typ chybového stavu, ako aj oddeliť kód, ktorý potenciálne generuje chyby, od kódu, ktorý ich spracováva.

Čokoľvek spôsobuje problémy, konečným výsledkom je, že aplikácia nefunguje podľa očakávania. Skôr než prejdeme k štruktúrovanému spracovaniu výnimiek, najprv si zopakujme tri najčastejšie používané výrazy na opis anomálií:

Softvérové ​​chyby

Toto je zvyčajne názov chýb, ktorých sa programátor dopúšťa. Predpokladajme napríklad, že aplikácia je vytvorená pomocou nespravovaného C++. Ak sa dynamicky alokovaná pamäť neuvoľní, čo by mohlo viesť k úniku pamäte, dôjde k chybe programu.

Používateľské chyby

Na rozdiel od softvérové ​​chyby, chyby používateľov sú zvyčajne spôsobené tým, kto aplikáciu spúšťa, nie tým, kto ju vytvára. Napríklad, ak koncový používateľ zadá do textového poľa chybný reťazec, tento typ chyby sa môže vygenerovať, ak kód nebol navrhnutý tak, aby spracovával chybný vstup.

Výnimky

Výnimky alebo výnimočné situácie sa zvyčajne nazývajú anomálie, ktoré sa môžu vyskytnúť počas behu a je ťažké, ak nie nemožné, predvídať počas programovania aplikácie. Medzi možné výnimky patria pokusy o pripojenie k databáze, ktorá už neexistuje, pokusy o otvorenie poškodený súbor alebo sa pokúša nadviazať komunikáciu so strojom, ktorý je tento moment je v offline. V každom z týchto prípadov programátor (a koncový užívateľ) môže s takýmito „výnimočnými“ okolnosťami urobiť len málo.

Z vyššie uvedených popisov by malo byť jasné, že štruktúrované spracovanie výnimiek v .NET je technika navrhnutá tak, aby sa vysporiadala s výnimkami, ktoré môžu byť vyvolané za behu. Aj v prípade softvéru vlastné chyby ktoré uniknú oku programátora, CLR však často automaticky vyhodí príslušnú výnimku aj s popisom aktuálny problém. Existuje mnoho rôznych výnimiek definovaných v knižniciach základných tried .NET, ako napríklad FormatException, IndexOutOfRangeException, FileNotFoundException, ArgumentOutOfRangeException atď.

V terminológii .NET sa „výnimka“ vzťahuje na chyby programovania, chyby používateľov a chyby za behu. Skôr než sa ponoríme do podrobností, pozrime sa, akú úlohu zohráva štruktúrované spracovanie výnimiek a ako sa líši od tradičných techník spracovania chýb.

Úloha spracovania výnimiek v .NET

Pred .NET, spracovanie chýb v prostredí operačný systém Windows bol veľmi mätúci mix technológií. Mnoho programátorov zahrnulo svoju vlastnú logiku spracovania chýb do kontextu aplikácie, ktorá nás zaujíma. Vývojový tím môže napríklad definovať množinu číselné konštanty reprezentovať známe situácie zlyhania a potom použiť tieto konštanty ako návratové hodnoty metódy.

Okrem techník, ktoré vymysleli samotní vývojári, Windows API definuje stovky chybových kódov pomocou #define a HRESULT, ako aj mnoho variácií jednoduchých booleovských hodnôt (bool, BOOL, VARIANT BOOL atď.). Okrem toho mnohí vývojári aplikácií C++ COM (a tiež VB 6) explicitne alebo implicitne používajú malú skupinu štandardných rozhraní COM (ako ISupportErrorInfo. IErrorInfo alebo ICreateErrorInfo) na vrátenie zmysluplných informácií o chybách klientovi COM.

Zjavným problémom všetkých týchto starších techník je nedostatok symetrie. Každý z nich viac-menej zapadá do rámca jednej technológie, jedného jazyka a možno aj jedného projektu. Podporované v .NET štandardný postup na generovanie a detekciu chýb v prostredí vykonávania, tzv štruktúrované spracovanie výnimiek (SEH) .

Krása tejto techniky je v tom, že umožňuje vývojárom zaujať jednotný prístup k riešeniu chýb, ktorý je spoločný pre všetky jazyky, ktoré sú zacielené na platformu .NET. Z tohto dôvodu môže programátor C# spracovávať chyby syntakticky rovnakým spôsobom ako programátor VB a programátor C++ pomocou C++/CLI.

Ďalšou výhodou je, že syntax, ktorú musíte použiť na vyhadzovanie a zachytávanie výnimiek mimo zostáv a strojov, tiež vyzerá identicky. Napríklad pri písaní v C# služby Windows Communication Foundation (WCF) môže vyvolať výnimku SOAP pre vzdialeného volajúceho pomocou rovnakých kľúčových slov, ktoré sa používajú na vyvolanie výnimky v rámci metód v tej istej aplikácii.