Programování v C# Další jazykové konstrukce Petr Vaněček 1 / 31
Obsah přednášky Přetěžování metody operátory Generika Kolekce třídy rozhraní 2 / 31
Překrytí vs. přetížení Rozdíl ve způsobu deklarace metody/operátoru deklarace: název a seřazený seznamu parametrů překrytí (override) stejný název, stejné parametry např. A.Tiskni(int i) a B.Tiskni(int i) přetížení (overload) stejný název, různé parametry např. A.Tiskni(int i) a B.Tiskni(float f) 3 / 31
Překrytí vs. přetížení Překrytí Shodná deklarace; nemůže být v jedné třídě Odděděné třídy mohou dodat vlastní funkčnost k metodě Pokud je metoda virtuální mechanismus polymorfismu použije se dynamicky určený typ např. A b = new B(); b.m(); volá B.M() Pokud není metoda virtuální použije se statický typ např. A b = new B(); b.m(); volá A.M() Přetížení Deklarace liší; může (nemusí) být ve stejné třídě 4 / 31
Přetížení Přetížené metody by měly poskytovat podobnou funkčnost vhodné používat v případě že metoda s méně parametry volá metodu s více parametry usnadňuje údržbu hlavní kód je jen na jednom místě usnadňuje práci pokud nepotřebujeme nějakou specialitku, stačí nám volat jednodušší metodu např. Open ( string name, FileMode mode ) {... } Open ( string name, FileMode mode, FileAccess access ) {... } pro jednoduchou práci nepotřebuju znát nic o typech přístupu 5 / 31
Přetížení Názvy parametrů by měly být samopopisné nepoužívat názvy parametrů jako s, i, cislo,... názvy u složitějších metod by navíc měly vypovídat o výchozí hodnotě např. int Compare ( string str1, string str2 ) { Compare (str1,str2, false ); } int Compare ( string str1, string str2, bool ignorecase ) {... } parametr ignorecase naznačuje, že není-li uveden bude záležet na velikosti písma 6 / 31
Přetížení Pořadí a názvy parametrů u přetížených metod by se neměly měnit usnadňuje volání rozšířených metod pouhým přidáním dalšího parametru Jako virtuální by měla být označena pouze kompletní metoda metody s nižším počtem parametrů ji volají většinou není důvod aby byly měněny U referenčních typů by se měla uvažovat i hodnota null stejné jako neudaný parametr otestuje se pouze na jednom místě a ne při každém volání 7 / 31
Operátory Jiný způsob zápisu funkce a + b Secti(a,b) Zpřehledňují zápis a zvyšují čitelnost kódu Používat s rozumem u datových typů u kterých operace dávají smysl v případech kdy je na první pohled zřejmé co má operátor dělat přetěžovat operátory symetricky když je operátor <, nadefinovat i > 8 / 31
Přetížitelné operátory Typy přetížitelných operátorů unární +, -,!,, ++, --, true, false binární +, -, *, /, %, &,,, <<, >> porovnání ==,!=, <, >, <=, >= konverzní operátory Částečně přetížitelné operátory přiřazovací +=, -=, *=, /=,... přetížené automaticky, pokud existuje odpovídající binární operátor podmínkové &&, lze obejít přetížením operátorů true a false 9 / 31
Vytvoření přetížení operátorů Operátory musí být public static Třída/struktura implementující operátor musí být alespoň jedním z operandů Unární operátory public static <typ> operator +(<typ> op) Binární operátory public static <typ> operator +(<typ> op1, <typ> op2) Explicitní typová konverze public static explicit operator <typ>(<typ> op) Implicitní typová konverze public static implicit operator <typ>(<typ> op) 10 / 31
Příklady struct Complex { public double im; public double re; public static Complex operator -( Complex op) { Complex res ; res.re = -op.re; res.im = -op.im; return res ; } public static Complex operator +( Complex op1, Complex op2 ) { Complex res ; res.re = op1.re+op2.re; res.im = op1.im+op2.im; return res ; } public static implicit operator double ( Complex op1 ) { return op1.re; } } 11 / 31
Obecné třídy Při psaní kódu jsou často potřebné datové struktury pro různé datové typy seznamy zásobníky fronty... Možné řešení využít OOP navrhnout třídu pro rodičovský typ (např. System.Object při přístupu využívat plymofrismus public class Zasobnik { object [] polozka ; public void Vloz ( object polozka ) {...} public object Vyber () {...} } 12 / 31
Nevýhody objektového řešení Nízký výkon u hodnotových typů musí dojít k boxing a unboxing volání metody zaměstnání GC ani při použití referenčních typů není vyhráno Typová (ne)bezpečnost explicitní přetypování Zasobnik z = new Zasobnik (); z. Vloz (3.3); int i = ( int )z. Vyber (); // výjimka 13 / 31
Specializované typy Možné řešení problémů vytvořit pro každý potřebný datový typ specializovanou třídu class IntZasobnik { int [] polozka ;... } Nový problém stejný (podobný) kód na více místech v případě chyby nákladná oprava 14 / 31
Co jsou generika Umožňují nadefinovat obecné třídy typová bezpečnost nedochází k přetypovávání, pracuje se přímo s požadovaným typem možno omezit typy, které mohou být použity snadná znovu využitelnost kódu stačí vytvořit instanci s požadovaným typem výkonost typová kontrola je provedena při překladu neprovádí se (un)boxing 15 / 31
Generika v.net Nově ve verzi 2.0 Součást CLI specifikace možno používat v ostatních.net jazycích Přímá podpora v IL generická třída se přeloží jako normální třída vyznačená místa pro nahrazení konkrétními typy k vytvoření konkrétní instance dochází až za běhu 16 / 31
Použití generik Lze použít pro třídy, struktury, rozhraní, metody a delegáty Příklad public class Zasobnik <T > { T[] polozka ; public void Vloz (T polozka ) {...} public T Vyber () {...} }... Zasobnik < int > z = new Zasobnik < int >(); z. Vloz (3); int i = z. Vyber (); Generický typ se uvádí v < > Název typu může být libovolný identifikátor používá se jednopísmenný, velké písmeno Při použití se musí uvádět konkrétní typ 17 / 31
Použití více typů Při deklaraci lze použít i více generických typů Příklad public { Uzel <K,H> K klic ; H hodnota ; Uzel <K,H> dalsi ; }... Uzel <int, string > uzel = new Uzel <int, string >(); 18 / 31
Omezení Problém při použití generických typů obecně můžeme za generický typ dosadit libovolný konkrétní typ nelze volat konkrétní funkce např. test na rovnost či porovnání nejsou součástí System.Object Možnost vymezit, které typy mohou být použity pomocí slova where třídy rozhraní new() musí mít neparametrický konstruktor struct musí být hodnotový typ class musí být referenční typ Příklad class PoleHodnot <T > where T : struct {... } 19 / 31
Kolekce Umožňují sdružovat položky stejného typu do skupin seznamy slovníky fronty... S příchodem.net 2.0 zavedení generických kolekcí větší efektivita vyšší typová bezpečnost vytvoření některých nový kolekcí 20 / 31
List<T> (ArrayList) Pole s dynamicky se zvětšující délkou Konstruktor možno nastavit počáteční délku vytvořit z pole (ICollection) Vlastnosti Count počet položek Capacity velikost pole Item indexový přístup k položkám Metody Add(item) přidá prvek na konec seznamu Remove(item) vyjme prvek RemoveAt(index) vyjme prvek na pozici Sort() setřídí pole BinarySearch() najde metodou půlení intervalu ToArray převede na pole 21 / 31
Další seznamy LinkedList<T> Dvojitě zřetězený seznam skládá se z uzlů LinkedListNode Rychlé operace vkládání a vyjmutí pomocí AddAfter/Before/First/Last, RemoveFirst/Last SortedList<T> Pole s binárním stromem ukládá se dvojice klíč/hodnota možnost indexovaného přístupu Vlastnosti Item, Keys, Values Metody Add, Remove, RemoveAt 22 / 31
SortedDictionary<T> Podobný jako SortedList dvojice klíč/hodnota vyhledávání pomocí stromu Používá pouze stromovou strukturu neumožňuje indexovaný přístup operace vkládání a vybírání O(logn) Vlastnosti Item[klíč] vrátí položku podle klíče Keys/Values kolekce klíčů/hodnot Metody Add/Remove přidá/ubere položku ContainsKey/Value dotaz zda obsahuje klíč/hodnotu 23 / 31
Dictionary<T> (HashTable) Hash tabulka dvojice klíč/hodnota rychlé operace (O(1)) Vlastnosti a metody podobné jako SortedDictionary 24 / 31
Porovnání metoda vkládání vyjmutí hledání reprezentace List O(n) O(n) O(n) pole LinkedList O(1) O(1) O(n) spojový seznam SortedList O(n) O(n) O(logn) pole+strom SortedDictionary O(log n) O(logn) O(logn) red-black strom Dictionary O(1) O(1) O(1) hash tabulka 25 / 31
Fronty a zásobníky Queue<T> Reprezentuje frontu Vlastnosti Count počet prvků ve frontě Metody Enqueue přidá prvek na konec fronty Dequeue odebere prvek ze začátku fronty Peak vrátí první prvek (bez odebrání) Stack<T> Reprezentuje zádobník Metody Push vloží prvek na vrchol Pop odebere prvek z vrholu 26 / 31
Rozhraní Collections Umožňují vytvářet vlastní kolekce snadná záměna jednoho typu za jiný používání ve foreach cyklech ICollection obecná kolekce vlastnosti Count počet prvků v kolekci IsReadOnly metody Add vložení prvku Remove odtranění prvku Contains zjištění zda prvek existuje Clear vymazání kolekce 27 / 31
Specializovaná rozhraní IEnumerable umožňuje použít kolekci ve foreach cyklu metoda GetEnumerator vrací enumerátor, lze použít klíčové slovo yield příklad struct Vektor : IEnumerable < int > { public int x,y,z; public IEnumerator < int > GetEnumerator () { yield return x; yield return y; yield return z; } IEnumerator IEnumerable. GetEnumerator () { return GetEnumerator (); } } 28 / 31
Specializovaná rozhraní IList potomek ICollection kolekce objektů přístupných pomocí indexů vlastnosti Item indexer, vrátí/nastaví prvek s indexem int i IsFixedSize kolekce s omezenou velikostí metody IndexOf vrátí index hledaného prvku (-1 v případě neexistence) Insert vloží prvek na pozici int i RemoveAt odebere prvek z pozice int i 29 / 31
Specializovaná rozhraní IDictionary potomek ICollection kolekce klíčů a hodnot vlastnosti Item indexer, vrátí/nastaví prvek s klíčem key Keys kolekce klíčů Values kolekce hodnot metody Add přidá dvojici klíč/hodnota ContainsKey zjistí zda klíč existuje Remove odebere prvek s klíčem key TryGetValue spojení ContainsKey a Item 30 / 31
Konec 31 / 31