230 likes | 329 Views
Računarski praktikum 3 Vježbe 07. Vinko Petričević. Iznimke. Delegati i događaji. Iznimke. Dio programa u kojem očekujemo neku anomaliju Iznimka najčešće sadrži neku informaciju o anomaliji
E N D
Računarski praktikum 3Vježbe 07 Vinko Petričević Iznimke. Delegati i događaji
Iznimke • Dio programa u kojem očekujemo neku anomaliju • Iznimka najčešće sadrži neku informaciju o anomaliji • Kada je iznimka “bačena” stog se odmotava i traži se handler koji će ju obraditi. Ako ju nitko ne obradi, program se “ruši” • Iznimka može biti tipa System.Exception ili iz nekog tipa izvedenog iz njeg (npr. u imenskom prostoru System imamo ArgumentNullException, InvalidCastException, OverflowException…)
Iznimke • Iznimku generiramo ključnom riječi throw, a metoga za hvatanje iznimki počinje sa catch, koji uvijek dolazi u paru sa try • Unutar try bloka navedemo kritičan dio kôda (unutar kojeg bi se mogao desiti throw), a nakon toga slijedi catch blok koji eventualnu iznimku obrađuje
Generiranje iznimke class Program { static void Main(string[] args) { Console.WriteLine("Ulaz u Main..."); f1(); Console.WriteLine("Main izvršena."); } static void f1() { Console.WriteLine("Ulaz u f1..."); f2(); Console.WriteLine("f1 izvršena."); } static void f2() { Console.WriteLine("Ulaz u f2..."); throw new System.Exception(); // izbacujemo iznimku Console.WriteLine("f2 izvršena."); } }
Hvatanje iznimke ... static void f2() { Console.WriteLine("Ulaz u f2..."); try { Console.WriteLine("Ulaz u try blok..."); throw new System.Exception(); Console.WriteLine("Izlaz iz try bloka..."); } catch { Console.WriteLine("Iznimka uhvaćena i obrađena."); } Console.WriteLine("Izlaz iz f2."); }
Zadatak • Izmijenite prethodni primjer, tako da se iznimka hvata u funkciji f1, te u main-u. Kometirajte što se mijenja
Namjenske iznimke • Često imamo različiti kôd za obrađivanje iznimaka različitog tipa. Osim takozvanog generičkoh catch bloka, možemo navesti tip iznimke koji on obrađuje (navodimo prvo specijalni tip) try { … } catch (System.DivideByZeroException) { Console.WriteLine("Iznimka dijeljenja s nulom uhvaćena!"); } catch (System.ArithmeticException) { Console.WriteLine("Aritmetička iznimka uhvaćena!"); } catch { Console.WriteLine("Nepoznata iznimka uhvaćena!"); }
Finally • Ponekad želimo izvršiti dio koda bez obzira na to da li se dogodila greška ili ne • Nakon eventualno obrađenih iznimaka, izvrši se finally blok try { … } catch { … } finally { Console.WriteLine(“Ovo se ce izvrsiti uvijek na kraju!"); }
Finally • Ponekad želimo izvršiti dio koda bez obzira na to da li se dogodila greška ili ne • Nakon eventualno obrađenih iznimaka, izvrši se finally blok try { … } catch { … } finally { Console.WriteLine(“Ovo se ce izvrsiti uvijek na kraju!"); }
System.Exception objekt • Svojstvo Message je readonly, i postavlja se prilikom kreiranja iznimke • Svojstvo HelpLink se može i mijenjati i služi da se omogući vezu do help datoteke sustava pomoći • Svojstvo StackTrace se može samo čitati i njega automatski postavlja .net framework static double Podijeli(double a, double b) { if (b == 0) { DivideByZeroException e = new DivideByZeroException(); e.HelpLink = "http://www.math.hr"; // postavljamo HelpLink throw e; } if (a == 0) { // Message možemo postaviti jedino kroz konstruktor throw new System.ArithmeticException("Nulu ne možete dijeliti!"); } return a / b; } …
System.ApplicationException • Ako nam normalne iznimke nisu dobre, možemo samo napraviti klasu (koja se najčešće izvodi iz ApplicationException), te u njoj možda dodati dodatne informacije o pogrešci
InnerException • Ako nismo do kraja obradili iznimku, možemo ju proslijediti dalje na obradu. U tom slučaju kreiramo iznimku, čije svojstvo InnerException postavimo na trenutnu iznimku, te ponovo bacimo tu novu iznimku
Delegati • nakon definiranja u njega možemo učahuriti bilo koju metodu s istim popisom parametara i povratnim tipom – slično kao pointeri na funkcije u C-u [modifikator pristupa] delegate NazivDelegata(potpisMetode); public delegate int KojiJePrvi(object o1, object o2);
Primjer 1 public class Osoba { public string ime, prezime; } public delegate int usporedi(Osoba o1, Osoba o2); class Program { public static int usporediPoImenu(Osoba o1, Osoba o2) { return o1.ime.CompareTo(o2.ime); } public static int usporediPoPrezimenu(Osoba o1, Osoba o2) { return o1.prezime.CompareTo(o2.prezime); } static void Main(string[] args) { usporedi u = new usporedi(usporediPoImenu); Osoba o1, o2; ... if (u(o1, o2) > 0) { ... } } }
Višeodredišni delegati • delegate možemo dodavati i oduzimati pomoću operatora + i – (odnosno += i -=), te će se onda osim jedne, izvršiti sve funkcije koje su dodane
Primjer 2 class KlasaSDelegatom { // deklaracija delegata public delegate void StringDelegat(string s); } class ImplementirajucaKlasa { public static void ZapisiString(string s) { Console.WriteLine("Zapisivanje niza znakova: {0}", s); } public static void ZabiljeziString(string s) { Console.WriteLine("Bilježenje niza znakova: {0}", s); } public static void PosaljiString(string s) { Console.WriteLine("Odašiljanje niza znakova: {0}", s); } }
Primjer 2 class Program { static void Main(string[] args) { // definiramo tri delegata tipa StringDelegat KlasaSDelegatom.StringDelegat Zapisivac, Biljeznik, Odasiljac; // definiramo još jednog delegata tipa StringDelegat KlasaSDelegatom.StringDelegat ViseodredisniDelegat; // instanciramo tri delegata Zapisivac = new KlasaSDelegatom.StringDelegat( ImplementirajucaKlasa.ZapisiString); Biljeznik = new KlasaSDelegatom.StringDelegat( ImplementirajucaKlasa.ZabiljeziString); Odasiljac = new KlasaSDelegatom.StringDelegat( ImplementirajucaKlasa.PosaljiString); // pozivamo metodu delegata Zapisivac Zapisivac("Niz znakova prosljeđen Zapisivaču"); // pozivamo metodu delegata Biljeznik Biljeznik("Niz znakova prosljeđen Bilježniku"); // pozivamo metodu delegata Odasiljac Odasiljac("Niz znakova prosljeđen Odašiljaču");
Primjer 2 Console.WriteLine("Viseodredisnidelegat = Zapisivac + Biljeznik"); // kombiniramo dva delegata u ViseodredisniDelegat ViseodredisniDelegat = Zapisivac + Biljeznik; // pozivamo 2 metode ViseodredisniDelegat-a ViseodredisniDelegat("Prvi prosljeđeni niz znakova "); Console.WriteLine("Viseodredisnidelegat += Odasiljac"); // dodajemo i treći delegat u ViseodredisniDelegat ViseodredisniDelegat += Odasiljac; // pozivamo 3 metode ViseodredisniDelegat-a ViseodredisniDelegat("Drugi prosljeđeni niz znakova"); Console.WriteLine("Viseodredisnidelegat -= Biljeznik"); // oduzimamo Biljeznika iz ViseodredisniDelegat ViseodredisniDelegat -= Biljeznik; // pozivamo 2 preostale metode ViseodredisniDelegat-a ViseodredisniDelegat("Treći prosljeđeni niz znakova"); } }
Anonimne metode • Da bi skratili pisanje kôda, delegate možemo koristiti za kreiranje anonimnih metoda • U vs2008 imamo lambda operator koji još pojednostavljuje kreiranje anonimnih metoda delegate int binOp(int x, int y); static void Main(string[] args) { binOp usp = delegate(int x, int y) { return x-y; }; }
Delegati i asinhrono pozivanje • Osim sinhronog pozivanja funkcija, delegati nam omogućuju i asinhrono pozivanje (što je objašenjno na kolegiju Distribuirani procesi - BeginInvoke) – kreira se novi thread koji izvršava metodu, a naš program nastavlja sa radom. • Rezultate asinhronog poziva možemo provjeriti sa EndInvoke
Događaji • Programi u grafičkim sučeljima moraju biti u stanji odgovarati na događaje • Događaj može biti pritisak na gumb, odabir opcije iz izbornika, događaj vremena i slično • U grafičkim sučeljima bilo koji objekt može pokrenuti događaj, a neki drugi objekt može biti zainterasiran za taj događaj. Tko će obraditi događaj nije bitno onome tko ga je pokrenuo • Kad neki objekt objavi događaj, svi objekti koji su pretplaćeni na taj događaj bivaju o tome obaviješteni
Događaji • U C# događaji se implementiraju pomoću delegata. Višeodredišni delegati nam omogućuju da se više objakata pretplati na neki događaj • Klasa izdavač definira delegat, a pretplatnička klasa koja se želi pretplatiti funkciju koja učahuri metodu koja će obrađivati događaj (event handler) • Prije kreiranja događaja, izdavač treba provjeriti je li itko prijavljan na događaj, jer ćemo u protivnom dobiti grešku
Događaji • Umjesto +=, za dodavanje novog preplatnika, mogli smo koristiti =, te bi prethodni pretplatnik mogao biti onda isključen, a delegat bi mogli pozvati i izravno • Zbog toga je ubačena ključna riječ event • Sada događaj može pokrenuti samo klasa koja ga je kreirala, te na njemu rade samo operatori += i -= public event RukovateljPromjenomSekunde NaPromjenuSekunde;