270 likes | 362 Views
Microsoft.NET környezet. Hernyák Zoltán Programozási Nyelvek II. Eszterházy Károly Főiskola Számítástudományi tsz. 1. Kivételkezelés - Exception Handling. class Verem { public Object Pop() { if (vm>0) { vm--; return t[vm]; } else ??? } }.
E N D
Microsoft.NET környezet Hernyák Zoltán Programozási Nyelvek II. Eszterházy Károly Főiskola Számítástudományi tsz 1
Kivételkezelés - Exception Handling class Verem { public Object Pop() { if (vm>0) { vm--; return t[vm]; } else ??? } } A fő kérdés: hogyan jelezze ez az eljárás azt, hogy nem lehet már kivenni elemet a veremből, mert a verem üres? 2
Kivételkezelés - Exception Handling • Hibajelzés első fontos kérdése: kinek jelezzük a hibát? • közvetlenül a felhasználónak: • Hangjelzéssel (beep) • Üzenet kiírásával (message) • Grafikus felületre (Dialog Box) • Konzolos felületre (Console.WriteLine) • Nyomtatóra • Napló file-ba (log file) írással • Program saját napló file-a • Windows központi napló file 3
Kivételkezelés - Exception Handling class Verem { public Object Pop() { if (vm>0) { vm--; return t[vm]; } else { hibajelzés; return ???; } } Object x = verem.Pop(); ... // x feldolgozása 4
Kivételkezelés - Exception Handling • Hibajelzés első fontos kérdése: kinek jelezzük a hibát? • jeleznünk kell a bennünket meghívó eljárásnak is, • hogy hiba történt a végrehajtás közben, a visszaadott • érték nem tekinthető feldolgozhatónak… ... else { hibajelzés; return null; } Object x = verem.Pop(); if (x==null) hiba_történt; else x_feldolgozása; 5
Kivételkezelés - Exception Handling Hibajelzés fontos szabálya: egyértelműen kiderüljön, hogy valóban hiba történt! verem.Push( null ); ... Object x = verem.Pop(); if (x==null) hiba_történt; else x_feldolgozása; Jelen esetben a Pop() visszatérési értékéből (hibásan) az következik, hogy hiba történt a Pop futása közben. 6
Kivételkezelés - Exception Handling Nagyon gyakori, hogy a fv-ek int típusú értékkel térnek vissza, ahol az egy hibakódot jelent. Leggyakrabban a 0 jelenti -> nem történt hiba, más értékek a hiba okának kódját jelölik. Ez nagyon rossz módszer, mert nincs szabvány a hibakódokra –> minden fv más-más kódolást használ – megjegyezhetetlen és kibogozhatatlan. Ráadásul, ha a hívó fél nem ír rögtön ‘if’-et a hívás után, akkor hiába adunk vissza hibakódot. Ez a hibajelzés csak újabb és újabb hibák előidézésre jó. Csak nagy odafigyelés mellett használható! 7
Kivételkezelés - Exception Handling Ráadásul konstruktorok esetén nem is használható! ( a konstruktornak nincs visszatérési típusa, értéke ) FileStream f = new FileStream(”C:\\hello.txt”); .. file feldogozása az ‘f’ példányon keresztül .. Ez a fenti sor elvileg megnyitná a megadott file-t olvasásra. De mi van, ha a file nem létezik, vagy nincs jogosultságunk megnyitni? Hogyan jelezzük a hibát? Itt nem megy a hibakód visszaadása… 8
Kivételkezelés - Exception Handling • Kivétel (Exception): • Ez egy jelzés, amelyet explicit módon indít el (lő fel) • a függvény, ha jelezni akarja a hívó fv-nek, hogy • hiba történt a végrehajtás közben • A fv a hiba jelzés után azonnal visszatér a hívás • helyére (azonnali return) • Ezen visszatérés rendhagyó, a visszatérési érték, • és a cím szerinti kimenő paraméterek értéke ekkor • nem definiált (e miatt nem is szabad felhasználni) • Ha a hívó ponton a feldobott kivételt nem kezeljük • le, akkor ezen fv is azonnal visszatér az őt hívó • helyre (hivási lánc visszagörgetése) 9
Kivételkezelés - Exception Handling • Kivétel (Exception): • Ha a feldobott kivételt a hivási verem egyik • mélységében sem kezeljük le, akkor minden fv • visszatér. A végén eljutunk a Main fv szintjére. • - Ha a Main() fv sem kezeli le a hibát, akkor a Main fv • is visszatér a hívási helyére – ez az operációs • rendszer. • Ez gyak. azt jelenti, hogy a program futása • befejeződik. 10
Kivételkezelés - Exception Handling class Verem { public Object Pop() { if (vm>0) { vm--; return t[vm]; } else throw new Exception(”Üres”); } } A hiba feldobását a ‘throw’ végzi. A throw paramétere egy Exception osztály (vagy vele kompatibilis) példány. 11
Kivételkezelés - Exception Handling Exception e = new Exception(”Üres”); throw e; Ritkán szoktunk ilyen kétlépéses példányosítást. Gyakrabban… throw new Exception(”Üres a verem”); A konstruktor egy string-et vár paraméterként. Ebben a string-ben egy hibaüzenet-et specifikálhatunk. Ha senki sem kapja el a hibát, és eljut az operációs rendszerig, akkor ez a hibaüzenet megjelenik egy párbeszéd-ablakban. 12
Kivételkezelés - Exception Handling • A System.Exception a legáltalánosabb hiba jelzés. • A hiba okát már a példány típusának kiválasztásával • is jelezhetjük: • System.ArithmeticException • System.ArrayTypeMismatchException • System.DivideByZeroException • System.IndexOutOfRangeException • System.InvalidCastException • System.NullReferenceException • System.OutOfMemoryException • System.StackOverflowException • System.TypeInitializationException 13
Kivételkezelés - Exception Handling A System.Exception osztályból számos gyerekosztály készült (hiba-hierarchia). Példa: System.ExceptionSystem.SystemExceptionSystem.IO.IOException System.IO.DirectoryNotFoundException System.IO.FileNotFoundException throw new FileNotFoundException(”Nincs meg a konfigurációs file!”); 14
Kivételkezelés - Exception Handling A kivétel elkapásához a try…catch blokkot kell használni. try { … … } catch (Exception e ) { … } Az a programszakasz, amelyik kivételt dobhat Itt dolgozzuk fel a kivételt ( mit kell csinálni, ha kivétel történt ) Itt specifikáljuk, milyen típusú kivételeket kívánunk elkapni Ezen a néven hivatkozhatunk a feldobott példányra a kivételt feldogozó kódban (változó-deklaráció) 15
Kivételkezelés - Exception Handling A Base Class Library metódusaihoz a help-ben le van írva, hogy milyen típusú kivételt dobnak… public StreamReader( string path ); 16
Kivételkezelés - Exception Handling A feldobott kivétel megvizsgálása: try { if (a==0) throw new DivideByZeroException(”az ‘a’ változó értéke 0”); else int c = b/a; … } catch (Exceptione ) { if (e is DivideByZeroException) { … } if (e.Message==”az ‘a’ változó értéke 0”) { … } } 17
Kivételkezelés - Exception Handling A feldobott kivétel típusa szerinti elágazás: try { … throw new DivideByZeroException(”az ‘a’ változó értéke 0”); } catch (DivideByZeroException e ) { … } catch (IOExceptione ) { … } catch (Exception e ) { … } Miért nem kezdhetjük az ‘Exception e’ esettel? Milyen kivételeket kap el az IOException eset? 18
Kivételkezelés - Exception Handling Saját kivételosztály használata: class sajatException:DivideByZeroException { public string valtozoNeve = String.Empty; public sajatException(string ValtozoNev) :base(”az ”+ValtozoNev+” változó 0 volt!”) { this.valtozoNev = ValtozoNev; } } try { … throw new sajatException(”a”); } catch (sajatException e ) { if (e.valtozoNeve==”a”) { … } } 19
Kivételkezelés - Exception Handling Elkaptunk egy kivételt… mit csináljunk ? Elkapjuk – feldolgozzuk … a kivétel megszűnik. try { … } catch ( Exception e ) { …. } Elkapjuk – megvizsgáljuk … a kivételt újra feldobjuk…. try { … } catch ( Exception e ) { if ( ??? ) throw e; } Másik kivételt dobunk fel… try { … } catch ( Exception e ) { if ( ??? ) throw new Exception(”…”); } 20
Kivételkezelés - Exception Handling Ha a példány bennünket nem is érdekel: Hiba: ‘e’ deklaráltuk, de nem használjuk fel! try { … } catch ( FileNotFoundException e ) { Console.WriteLine(”Nem megfelelő file név!”); } Helyesen… try { … } catch ( FileNotFoundException ) { Console.WriteLine(”Nem megfelelő file név!”); } 21
Kivételkezelés - Exception Handling Nagyon gyakori eset: erőforrás lefoglalása (inicializálás) … try { … } catch ( Exception e ) { } erőforrás felszabadítása … throw e; // a hiba továbbdobása, de ez sajnos nem jó itt Ez meg nem elegáns: 1: nincs ‘e’ változó itt 2: csak akkor kell tovább dobni, ha volt is hiba erőforrás lefoglalása (inicializálás) … try { … } catch ( Exception e ) { erőforrás felszabadítása … throw e; } erőforrás felszabadítása … 22
Kivételkezelés - Exception Handling A megfelelő megoldás: erőforrás lefoglalása (inicializálás) … try { … } finally {erőforrás felszabadítása …} A ‘finally’ ág akkor is végrehajtódik, ha a try szakaszban Exception dobódik fel, és akkor is, ha nem. A ‘finally’ nem szedi le a hibát, a hiba attól feldobva marad, a finally blokkból kilépve újra érvényre jut, és visszatér a hívás helyére. 23
Kivételkezelés - Exception Handling public int Akarmi() { try { … } finally { … } return 0; } A ‘return 0’ csak akkor hajtódik végre, ha a try blokkban nem volt exception feldobva! Ha feldobásra került, akkor a finally blokk végrehajtódik, de a ‘return 0’ már megint nem… 24
Kivételkezelés - Exception Handling A blokkok egymásba ágyazhatók: try { try { … } finally { … } } catch (Exception) { … } 25
Kivételkezelés - Exception Handling A típus nélküli catch ekvivalens a Exception típusú catch-al (de ilyenkor nem lehet hivatkozni a catch blokkon belül a kivétel-példányra) : try { … } catch { … } 26
Kivételkezelés - Exception Handling Ez a sorrendbe kapcsolás megengedett egymásba ágyazás nélkül is: try { … } catch { … csinálunk valamit … throw; } finally { … } A try-finally-catch sorrend viszont nem! 27