V 1.0 Szabó Zsolt, Óbudai Egyetem, Programozási Paradigmák és Technikák Programozási eszközök Interfészek Generikus osztályok Operator overloading Adatstruktúrák Láncolt Lista Bináris fa Gráfok Dijkstra algoritmus Kruskal algoritmus
V 1.0 Szabó Zsolt, Óbudai Egyetem, Programozási Paradigmák és Technikák Programozási eszközök Interfészek Generikus osztályok Operator overloading Adatstruktúrák Láncolt Lista Bináris fa Gráfok Dijkstra algoritmus Kruskal algoritmus
V 1.0 Szabó Zsolt, Óbudai Egyetem, Metódusok "előírására", kötelezővé tételére használható Az osztályban kötelezően kell lennie egy publikus Eldönt() eljárásnak (ha nincs: a fordító reklamál) Hasonló, de teljesen másra használt: absztrakt osztály Kifejezés: "az X osztály, struktúra implementálja az Y interfészt" Interfészek
V 1.0 Szabó Zsolt, Óbudai Egyetem, Egy interfészt implementáló osztály példányosítható egy interfész típusú változóba: IEldönthető valtozo=new SajátOsztály(); Egy interfész-metódus elérhető az osztálypéldányon keresztül: SajátOsztály valtozo=new SajátOsztály(); valtozo.Eldönt(); … Vagy az interfészen keresztül: (valtozo as IEldönthető).Eldönt(); Ez utóbbira akkor van szükség, ha explicit megvalósítású az interfész az osztályban, vagy a változó típusából nem egyértelmű az interfész implementálása Interfészek - lehetőségek
V 1.0 Szabó Zsolt, Óbudai Egyetem, Explicit implementáció Azonos eljárást előíró interfészek esetén lehet szükséges
V 1.0 Szabó Zsolt, Óbudai Egyetem, Explicit Implementáció
V 1.0 Szabó Zsolt, Óbudai Egyetem, Explicit implementáció használata A következő órán fogunk saját interfészt létrehozni, ezen az órán csak meglévő interfészeket használunk
V 1.0 Szabó Zsolt, Óbudai Egyetem, Interfészek használata Tipikusan: funkcionalitás előírásánál, avagy előírásnak megfelelésnél (pl. VEP: ha az INotifyPropertyChanged interfészt implementálom egy olyan osztálynál, aminek a példányait ListBox vezérlőben helyezem el, akkor ez előír egy eseményt, amire a ListBox feliratkozik – ezen az eseményen keresztül tudja a ListBox, ha frissítenie kell) "A változó típusából nem egyértelmű az interfész implementálása" Ugyanaz, mint amikor OOP-ben ős típusú volt a tömb, és nem tudtuk, hogy az egyes tömbelemek milyen típusúak Van olyan eset, amikor a gyűjteményből/tömbből csak néhány elem implementál egy bizonyos interfészt, az interfész implementálását ugyanúgy az IS kulcsszóval lehet ellenőrizni
V 1.0 Szabó Zsolt, Óbudai Egyetem, Interfészek használata
V 1.0 Szabó Zsolt, Óbudai Egyetem, Array.Sort(tömb) tömb rendezése. int[] esetén tökéletesen működik Készítsünk egy osztályt, amelynek segítségével hallgatókat tudunk tárolni: név, neptun kód, teljesített kreditek Töltsünk fel egy 10 elemű tömböt hallgatókkal. Hogyan tudjuk ezt a tömböt a fenti módon névsorba vagy teljesített kreditek szerinti sorba rendezni? IComparable IComparable.CompareTo(object) Interfészek használata
V 1.0 Szabó Zsolt, Óbudai Egyetem, Programozási Paradigmák és Technikák Programozási eszközök Interfészek Generikus osztályok (© Erdélyi Krisztina) Operator overloading Adatstruktúrák Láncolt Lista Bináris fa Gráfok Dijkstra algoritmus Kruskal algoritmus
V 1.0 Szabó Zsolt, Óbudai Egyetem, Generikus Osztályok A generic fogalma Generikus osztályok Generikus metódusok Megszorítások Statikus tagok Öröklés A generic-ek működése.NET-ben
V 1.0 Szabó Zsolt, Óbudai Egyetem, Bevezetés Klubok (angol-társalgás, kirándulás) tevékenységét segítő szoftvert szeretnénk készíteni. Fontos, hogy egy személy egyetlen egyszer szerepeljen egy klubban, hiszen különben a két „példánya” önálló életet élne. Hogyan célszerű ezt megvalósítani? Próbáljuk minél általánosabban megoldani a feladatot! Lehet, hogy jövőre kutya-klubos szoftvert kell készítenünk.
V 1.0 Szabó Zsolt, Óbudai Egyetem, Bevezetés – megoldási javaslatok Célszerű halmaz típust létrehozni, mert az egy elemet egyszer tartalmazhat Milyen elemekből álljon a halmaz? –Személy – akkor a kutya-klubhoz át kell írni –A személy és a kutya őse – ez biztos, hogy elég általános? –Object ez mindennek az őse - ez lehet megoldás ArrayList,.NET1, csak object-et tárol, állandó castolás –A típust adjuk meg paraméterként, így elég a deklarációban megadni a konkrét típust – ez is megoldás Vizsgáljuk meg ezt közelebbről!
V 1.0 Szabó Zsolt, Óbudai Egyetem, A generic fogalma.NET-ben Paraméterezett típus vagy metódus Mindenegyes paraméter egy még meg nem határozott típus helye Más néven sablon vagy template Az osztály deklarációjakor csak T néven hivatkozok a típusra, csak az osztály példányosításakor definiálom, hogy ez a T pontosan mi
V 1.0 Szabó Zsolt, Óbudai Egyetem, Paraméterezett típusok A paraméter a típus fejrészében helyezkedik el class MyGenericClass { } Deklarációnál és példányosításkor az aktuális típus kerül a paraméter helyére MyGenericClass mgcINT = new MyGenericClass (); A generic-ek tipikusan gyűjtemények létrehozásához valók, mivel a gyűjtemények több típussal is használhatók
V 1.0 Szabó Zsolt, Óbudai Egyetem, Generikus gyűjtemények ArrayList object típust tárol, állandó castolás, elavult List : Add(), Insert(), Remove(), RemoveAt(), Reverse(), [], Clear(), Contains(), Count Queue : Enqueue(), Dequeue(), Peek(), Clear(), Contains(), Count Stack : Push(), Pop(), Peek(), Clear(), Contains(), Count Dictionary : Add(), Remove(), TryGetValue(), Keys, Values, Clear(), ContainsKey(), ContainsValue(), Count
V 1.0 Szabó Zsolt, Óbudai Egyetem, Saját generikus osztály létrehozása
V 1.0 Szabó Zsolt, Óbudai Egyetem, Generikus osztály használata
V 1.0 Szabó Zsolt, Óbudai Egyetem, Paraméterezett típus inicializálása Nem tudható, hogy érték vagy referencia típusú-e a paraméter Megoldás: default expression –Referenciánál null-t ad vissza –Érték típusnál bitenkénti nullát this.elem = default(T);
V 1.0 Szabó Zsolt, Óbudai Egyetem, Megszorítások Lefordulnak a következő kódok? Ha nem, akkor mi a megoldás? Annyit feltételezhetünk, hogy a T típus a System.Object-ből származik Ezért ennek megfelelően viselkedik
V 1.0 Szabó Zsolt, Óbudai Egyetem, class MyClass2 where T : IEnumerable { public void Iterate(T data) { foreach (object item in data) { Console.WriteLine(item); } Interfész megszorítás class MyClass2 { public void Iterate(T data) { foreach (object item in data) { Console.WriteLine(item); } Nem biztos, hogy T felsorolható! (A foreach ciklus akkor működik saját típuson, ha a saját típus megvalósítja a IEnumerable interfészt, ld. később) OK
V 1.0 Szabó Zsolt, Óbudai Egyetem, Konstruktor megszorítás class MyClass { T obj = new T(); } class MyClass where T:new() { T obj = new T(); } Nem biztos, hogy T-nek van alapértelmezett konstruktora! OK
V 1.0 Szabó Zsolt, Óbudai Egyetem, Művelet megszorítás??? class Arithmetic { public T Cubed(T number){ return number * number * number; } class Arithmetic where T : System.Int32{ public T Cubed(T number){ return number * number * number; } Nem biztos, hogy T-n értelmezett a szorzás! Érték és primitív típusok nem lehetnek megszorítások! Súlyos korlátja a generic-ek használatának, hogy standard operátorok az érték típusokkal nem használhatók.
V 1.0 Szabó Zsolt, Óbudai Egyetem, A Generic korlátja class Program2 { public T Min (T a, T b) where T : IComparable { if (a<b) return a; else return b; } class Program { public T Min (T a, T b) where T : IComparable { if (a.CompareTo(b)<0) return a; else return b; }… } A standard operátorok nem használhatók.
V 1.0 Szabó Zsolt, Óbudai Egyetem, Megszorítások A megszorítások a típus paraméterektől elvárt viselkedést írják le A where kulcsszóval vezetjük be Típusnál és metódusnál is használhatók Fajtáik: –Leszármazott (where T : Személy) –Interfész (where T: IEnumerable ) –Érték típus (where T: struct) –Referencia típus (where T: class) –Konstruktor (where T: new()) Az alábbi típusok nem lehetnek megszorításban: –Lezárt osztályok –Primitív típusok –System.Array –System.Delegate –System.Enum –System.ValueType
V 1.0 Szabó Zsolt, Óbudai Egyetem, Generikus metódus Tartozhat generikus vagy nem generikus típushoz Attól mert, a típus generikus, a metódus még nem A metódus generikus, ha saját típusparamétere(i) van(nak) A típusparaméter megjelenhet visszatérési értékként vagy a paraméterlistában
V 1.0 Szabó Zsolt, Óbudai Egyetem, Generikus metódusok meghívása A metódus meghívásakor a paraméterek típusa adja meg a típusparaméter aktuális értékét: int i=Min(2, 3); //egészek float f=Min(2.0, 3.0); //valósak Ellentmondás esetén a nem-generikus eljárás hívódik: mi van, ha T=int? a nem-generikus változat hívódik meg Ha két generikus metódus van különböző generikus paraméterrel pl. Method(T arg), Method(U arg), és T és U konkrétan ugyanaz, akkor a metódus meghívásánál jelez hibát.
V 1.0 Szabó Zsolt, Óbudai Egyetem, Statikus tagok A statikus tagok eléréséhez be kell helyettesíteni egy konkrét típust a paraméterbe MyGenericClass.Count(); Különböző behelyettesített típusokhoz különböző statikus tagok tartoznak A statikus konstruktor implicit meghívódik, és a behelyettesített típusnak megfelelően inicializálja a statikus mezőket
V 1.0 Szabó Zsolt, Óbudai Egyetem, Példányok számolása class MyGenericClass { private static int counter = 0; public MyGenericClass() { counter++; } public static void Count() { Console.WriteLine(counter); }
V 1.0 Szabó Zsolt, Óbudai Egyetem, Generikus osztályok az öröklésben Generikus osztály lehet őse generikus és nem generikus osztálynak Generikus osztály származhat generikus vagy nem generikus osztályból De mindkét állítás csak bizonyos esetekben igaz! Gondoljunk arra, hogy az utód példányosításakor a típusparaméterek értékét mindenképpen meg kell határozni
V 1.0 Szabó Zsolt, Óbudai Egyetem, Generikus osztályok az öröklésben Melyik eset lehetséges?
V 1.0 Szabó Zsolt, Óbudai Egyetem, Generikus osztályok az öröklésben és a.NET-ben A típusra vonatkozó ős osztálybeli megszorításokat az utódosztályban meg kell ismételni Az utódosztály tartalmazhat további megszorításokat Nem nyelvspecifikus, minden felügyelt nyelvben elérhető A köztes kódra való fordítás során metaadatok és a generic-ekre vonatkozó MSIL kód áll elő A JIT fordítás során történik meg a konkrét típusok behelyettesítése Lehetőség van több típus használatára: class valami { }
V 1.0 Szabó Zsolt, Óbudai Egyetem, A generic-ek működése.NET-ben A fenti kódhoz három osztály jön létre. A két MyGenericClass osztozik egy osztályon. A MyGenericClass külön osztály. A MyGenericClass és a MyGenericClass osztozik egy osztályon.
V 1.0 Szabó Zsolt, Óbudai Egyetem, Feladat: halmaz Hozzunk létre egy generikus halmaz osztályt, amelyben List segítségével tároljuk az elemeket Kell: konstruktor, copy konstruktor, elem hozzáadása Cél: foreach ciklus működjön:
V 1.0 Szabó Zsolt, Óbudai Egyetem, IEnumerable / IEnumerator A foreach ciklus akkor működik saját típuson, ha a saját típus megvalósítja a IEnumerable interfészt Ez az interfész előírja a GetEnumerator() eljárást, ami visszaad egy olyan objektumpéldányt, ami megvalósítja az IEnumerator interfészt Az IEnumerator előírja a következő műveleteket: Aktuális elem olvasása (Current), következő elemre mozgás (MoveNext()), visszaállás az első előtti elemre (Reset()) lista bejárása Mindegyik interfész előírja a nemgenerikus (object) változatot is Saját enumeratort a következő órán fogunk implementálni, addig meglévő enumeratort használunk
V 1.0 Szabó Zsolt, Óbudai Egyetem, Programozási Paradigmák és Technikák Programozási eszközök Interfészek Generikus osztályok Operator overloading Adatstruktúrák Láncolt Lista Bináris fa Gráfok Dijkstra algoritmus Kruskal algoritmus
V 1.0 Szabó Zsolt, Óbudai Egyetem, Operator Overloading halmaz ha = new halmaz (); halmaz hb = new halmaz (); ha.hozzaad(42); hb.hozzaad(15); ha.hozzaad(23); halmaz hc = ha + hb; unió public static halmaz operator +(halmaz h1, halmaz h2) { } halmaz hc = ha - hb; különbség halmaz hc = ha * hb; metszet halmaz hc = ha + 5; elem hozzáadása halmaz hc = ha - 5; elem törlése A kimenet mindig ÚJ objektumpéldány Új operátort nem lehet feltalálni Az azonos/hasonló operátorok lehetőleg hivatkozzanak egymásra
V 1.0 Szabó Zsolt, Óbudai Egyetem, Operator Overloading Implicit konverzió, T halmaz –halmaz ha = 5; halmaz hb="Hello"; –public static implicit operator halmaz (T elso) { } Explicit konverzió, halmaz string –string valami = (string)ha; –public static explicit operator string(halmaz be) { } Ugyanarra a típusra nem lehet mindkettő konverziót definiálni! A kimeneti típus vagy a bemeneti típus kötelezően az operátort tartalmazó osztály! if (ha==hb) / if (ha!=hb) / if (ha.Equals(hb)) Equals: példányok tartalmi egyezés-vizsgálata. Sok mező/beágyazott osztály esetén inkább javasolt: GetHashCode()
V 1.0 Szabó Zsolt, Óbudai Egyetem, Tesztelés
V 1.0 Szabó Zsolt, Óbudai Egyetem, Képek forrásai