C# 2008
Základy jazyka
- Proměnné. Vždy obsahují datový typ a nelze jej měnit. Dovozené (var).
- Obor viditelnosti proměnné - členská proměnná třídy => lokální proměnná (v bloku nebo metodě) => for/while
blok
- Konflikty viditelnosti řeší prefix. Tj. this, jméno třídy u static, namespace
- Konstanty - musí být známy v době překladu a jsou statické
- Datové typy předdefinované - celočíselné (sbyte,short,int, long, byte,ushort,uint,ulong),float, double,
decimal, bool,char
- Referenční typy předdefinované - object, string
- Příkazy pro řízení běhu programu - Sekvence, Podmínky, Iterace, Jump (if else, switch case default) (do
while for foreach) (return, continue greak goto)
- Výčtové typy (enumerátor)- uživatelskyy definovaný celočíselný typ.
- Pole - referenčnín typ
- Jmenné prostory. namespace{}. Pro logické seskupení souvisejících tříd a typů. (nikoli fyzické - to
zajišťujhí soubory, komponenty). Lze je vnořovat do sebe. using. using aaa=Wrox.abcd.aaa - lze tak pomocí
alias zkracovat namespace.
- Překlad souborů - csc /t:exe (library, module, winexe) tjh. konzole, knihovna, modul (bez manifetstu), s
GUI.
- Dokumentace XML - strukturované komentáře umožňují tvořit dokumentaci funkcí přes tři lomítka ///. Např.
<param>,<returns><summary><value> popisuje vlastnost<exception> - popis
vyjímek<example>-zvýrazňuje kus kódu
- Direktivy preprocesoru (#define,#undef, #if,#else,#elif,#enfif, #warning,#error, #region,#endregion, #line,
#pragma - +disable/restore)
Objekty a Typy
- Třídy a struktury jsou šablony, podle nichž se tvoří objekty (instance). Objekty obsahují data (datové
členy) a metody pro manipulaci s nimi (funční členy).
- Struktury se liší umístěním v paměti, nelze dědit, default konstruktor inicializuje datové typy (nelze
napsat vlastní prázdný konstruktor). sA = sB - dojde ke zkopírování obsahu struktury a né k zkopírování
odkazu (dá se ale použít ref). Z toho plyne, že se struktury hodí pro malé množství dat. Jsou odvozeny od
System.ValueType a né od System.Object.
- Členy třídy jsou buď instační nebo statické. Dělíme je na datové (datové složky, konstatnty a události) a
funkční (metody, vlastnosti, konstruktory, finalizéry, operátory a indexery)
- Parametry lze předávat odkazem nebo hodnotou. I struktury lze předávat odkazem (ref, out). Přetěžování metod
lze typem, počtem, pořadím, ale né návratovou hodnotou, deklarací ref/out nebo volitelnýmí parametry
- Properties-vlastnosti. Chovají se jako datová složka, ale mají metody get/put. Lze mít vlastnosti jen pro
čtení, nebo pro zápis. Lze měnit i viditelnost.
- Konstruktory. Bez návratového typu + stejné jméno jako třída. Implicitní konstruktor nastaví datové složky
na výchozí hodnoty. Statické konstruktory se nebijí s instančními a jsou spuštěny někdy (ale vždy před
prvním použitím třídy) - vždy bez parametrů. Volání konstruktorů z jiných konstruktorů :this() a base().
This zavolá konstruktor ve své třídě a base v rodičovské třídě. Max jedno volání.
- Konstanty a readonly (static/instanční). Readonly lze nastavovat za běhu programu z konstruktorů. Např
načtené hodnoty z konfiguračních souborů. To konstanty neumí.
- Anonymní typy - var doctor = new {FirstName="a", LastName = "b"}; Nebo ještě jednodušeji var osoba = new
{objX.FirstName, objX.LastName}; Skutečný typ neexistuje. Překladač jim přiřadí unikátní číslo.
- Struktury - seskupenín datových položek, vždy public (pokud potřebuješ private zvaž třídu). Mají pevně
zabudovaný konstruktor, který inicializuje datové členy.
- Třída vers. Struktura. Referenční/hodnotový typ, Bez dědičnosti, výchozí konstruktor (nelze přepsat), u
struktur lze uspořádat datové složky v paměti. Ale pozor struktury mohou implementovat rozhraní.
- Partial class - Částečné třídy. Umožňuje mít jednu třídu ve více souborech. Klasicky Wizard vytvoří A a
programátor B a to vše v jedné třidě, ale ve dvou souborech.
- private, protected, internal, public, abstract, sealed, partial
- Třída Object - GetType(), ToString(), GetHashCode(), Equals(Object), Equals(Object, Object), Finalize(),
MemberwiseClone(),ReferenceEquals(Object, Object)
- Rozšiřující metody
public static void ExMethod(this MyClass myClass, int par1,...){}. Když to nejde děděním.... Pozor, nelze takto přepisovat již existují metody - instační má vždy přednost.
4 Dědění
- Dědí se implementace (0-1x) nebo rozhraní (0-nx). Vícenásobné dědení není podporováno (tj. z více tříd
najednou). Přesněji řečeno, každá třída dědí. Když není uvedeno tak z Object. (Struktury dědí z ValueType).
Přesněji řečeno ze struktur nelze naprogramovat hierarchii typů.
- Dědit lze implementaci nebo jen abstrakce. System.Object = object.
- Virtuální metody VirtualOverride.cs - umožníme překrytí
metody/vlastnosti nějakou z odvozených tříd. V C# nejsou metody standardně virtuální. Klíčové slove
override - co znamená že metoda v odvozené třídě překrývá metodu v základní třídě.
- Nelze překrýt konstruktor, datové členy, vše statické. Lze překrýt pouze instanční metody a vlastnosti.
- Zastiňování metod (shading) VirtualOverride.cs. Lze
zastínit metodu se stejnou signaturou, která ale není override. Použij new - nebo dostaneš warning. Je to
ale nedoporučovaná operace.
- Abstraktní metody - Abstract.cs. Nelze z ní udělat instanci - funguje
jako rozhraní, ale s možností mít datové členy. Abstraktní metody je třeba překrýt (override). Je implicitně
virtuální.
- Zapečetěné třídy - pokud nechceš umožnit dědění. Důvod je utajení nebo jistota, že jakékoliv dědění je
zbytečné a mohlo by naopak způsobit problémy.
- Konstruktory. Pokud vytvoříš konstruktor s parametry nebude implicitní konstruktor spuštěn. Private
konstruktor znemožní vytvoření instance třídy. (Např. pokud tvoříš Factory a chceš třídy tvořit z metod).
Statický konstruktor jen bez prametrů.
- Volání konstruktoru z jiných konstruktorů. Je třeba vědět že pořadí volání konstruktorů je od System.Object
až po poslední zděděný. Rozlišovat this a base.
- Modifikátory viditelnosti
- public - pro libovolný kód
- protected - pro typ do kterého patří a všechny odvozené typy.
- internal - pouze pro sestavení v němž se nachází.
- private - pouze v typu do kterého patří
- protected internal dohromady oba dva (ve stylu OR)
- Další modifikátory
- new - skrývá zděděný člen se stejnou signaturou
- static - není instanciován - člen třídy
- virtual - člen může být překryt v odvozené třídě
- abstract - bez implementace. Jen definuje signaturu (rozhraní členu). Vždy virtual.
- override - Člen překrývá virtuální nebo abstraktní člen rodičovské třídy
- sealed - U třídy nelze odvozovat potomky. U metod/vlastností - nelze překrýt
- extern - pouze statické metody. DllImport. Rozhraní metody v jiném jazyku.
- Rozhraní - nemá konstruktor ani datové složky. Jen deklaruje. Lze deklarovat metody, vlastnosti, indexery a
události. Vždy implicitně public ale není možné to definovat.
- Odvozená rozhraní - rozhraní mohou od sebe dědit. Hezký příklad je s rozhraním IBankAccount,, které je
zděděno do ITransferBankAccount, kde v jediné metodě TransferTo() přesunuje peníze z banky do banky. Child
class k tomu ale využívá metody z rodičovského rozhraní IBankAccount. BankAccount.cs
5 - Pole
- Za vším je skrytá třída Array. Ta nabízí metody pro třídění a filtrování polí. Pole obsahuje několik/řadu
objektů stejného typu. Deklarate typ[] A1; Inicializace int[] A2 = new int[4]; Pole je refernčního typu,
takže Inicializace vytvoří místo "přesné délky" na haldě.
- Pole tedy využijeme zpravidla pokud dopředu známe jeho délku. Pokud né použijeme radši kolekce.
- Různé zápisy: int[] A2 = new int[4]; int[] A2 = new int[4] {1,2,3,4}; int[] A2 = new int[] {1,2,3,4}; int[]
A2 = {1,2,3,4}; Parametry indexů jen celá čísla. (Vlastní indexery mohou mít i jiné indexy).
- Práce s poli je přiřazení, čtení a procházení (for int i=0; i
- Prvky pole mohou být datové typy nebo objekty. Pro referenční typy musí být alokována paměť. Nelze pracovat
s null.
- Více rozměrná pole A[5,2], nepravidelná pole Jagged[5][]
- Array - nelze z ní přímo dědit, ale syntaxí jazyka C#, vlastně vytvoříme zděděnou třídu Array. To lze obejít
přes Array.CreateInstance(typeof(int),10). Pokud ale vytvořenou array rovnou nepřetypuješ (int[] A2 =
(int[]) newArray), tak pak nemůžeš použít indexy a musíš přes SetValue()/GetValue(). Asi protože překladač
nezná délku prvku pole.
- Length(), LongLength()-vrací délku v long, Rank()- vrací dimension
- Kopírování polí. Clone() - implementuje rozhraní ICloneable. Další možnost je statická Copy(). Ale ta už
potřebuje definované pole. Vždy se vytváří mělká kopie.
- Třídění polí. Sort(). Pro třídění vyžaduje aby prvky pole implementovaly rozhraní IComparable.
Array.Sort(person). Nebo lépe přes rozhraní IComparer, které umožní ještě definovat podle čeho třídit.
Array.Sort(persons, new PersonComparer(PersonComparer.PersonCompareType.FirstName)). Sort ještě poskytuje
rozhraní pro delegáty.
- Rozhraní - IEnumerable (pro foreach), ICollection (Count,CopyTo(),IsSynchronized=false), IList ( Clear()
udělá null, Contains() true/false, IndexOf() dtto jen index prvního prvku, Item() +celočíselný index,
IsFixedSize = true, IsReadOnly = false, Add()+Insert()+Remove()+RemoveAt() NotSupportedException )
- IEnumerator - rozhraní MoveNext(), Current, Reset().
- yeild return - usnadňuje vytváření Enumeratoru. V podstatě se tím dá vráti Pole (kolekce). Odporně - Metoda
či vlastnost obsahující yeild se označuje jako blok iterátoru. Vrací rozhraní IEnumerable/IEnumerator. Lze
použít yeild return, yeild break ale né return.
- Lze jednoduše ve třídě naimplementovat metody Reverse(), Subset(), které vracejí IEnumerable jednu Array
různými způsoby. Samozřejmě musí existovat GetEnumerator() aby existovalo aspoň jedno rozhraní IEnumerable.
- yeild lze použít i složitější metodou, kdy vrací další enumerátor a ty pak máš rekurzi. Viz TicTacToe
Operátory a přetypování
-
- + - * / % - Aritmetické
- & ! | ~ && || - Logické
- + - Spojování řetězců
- ++ -- - Incremet, decrement
- << >> - bitový posun
- == != > < <= >= - porovnání
- = += -= *= /* %= &= |= ^= <<= >>= - Přiřazení (složené operátory)
- . - přístup k členům objektů a struktur
- [] - Indexovní pro pole a indexery
- () - přetypování
- ?: - ternální operátor (podmínka)
- + - - Spojování a odebírání delegátů
- new - vytváření objektů
- sizeof, is typeof as - informace o typu. is je kompatibilní s typem (přímo nebo přes
potomka). as - explicitní převod (nejde li pak null). sizeof velikost v bytech, typeof vrací
System.Type.
- checked, unchecked - řízení vyjímek přetečení
- :: - Kvalifikátor aliasu jmenného prostoru
- ?? - Operátor nulového sjednocení
- Typová bezpečnost. C#, rrsp IL vyžaduje silnou typovou bezpečnost. Implicitní převod (z long na int a
zpět-to ale nejde) jen z menších na větší. Nelze null type na notnull (int? na int).
- Explicitní převod - autor ví co chce. Může dojít ke ztrátě dat (unchecked implicitně). MAX int = 2147483647
- Automatické zabalování a vybalování boxing/unboxing. Datové typy na Referenční typy a zpět. int i = 10;
object o = i; int j = (int) o; Když nejde InvalidCastException. (Třeba o je long)
Delegáty a události
- Pokud potřebujeme předat adresu nějaké funkce do jiné třídy . Např. při volání podprocesů (thready), při
třídění v generických třídách, události - informují o nějaké změně stavu, nové události
- Delegáty - zástupci metod. Tj adresa na funkci, ale typově zabezpečená. Delegát ale fyzicky obsahuje jen
adresu.
- Delegát vytvoříme deklarací a zároveň naprogramuje metodu, která splňuje deklaraci. Metoda bude následně
instanciována 1x i vícekrát. (delegate int IntMethodInvoker(int x);). Každý delegat je vlastně třída
odvozená od System.MultiCastDelegate.
- private delegate string GetAString(); odkaz na metodu co vrací string a nepřijímá žádný parameter.
int x = 40; GetAString StringMethod = new GetAString(x.GetHashCode().ToString); jako metodu použijeme
ToString - instanční metoda z int.
- Volání se dá zkrátit tzv. inference - dovození GetAString StringMethod = x.GetHashCode().ToString;.
Syntactics sugar, protože překladač přeci ví, že StringMethod je delegát. V každém případě překladač vytvoří
novou instanci.
- Vícenásobné delegáty - += -= delegáty lze zřetězovat. Např při obClick metodě lze udělat více akcí najednou.
Pořadí volání není zaručeno. Další problém jsou vyjímky. Stačí aby u prvního systém vyvolal vyjímku a
neprojde žádný další. Třída Delegate má metodu GetInvocationList a tak můžeš procházet seznam volání podle
sebe. Je pak zaručeno pořadí i lzeošetřit vyjímky.
- Anonymní metody. Je v podstatě delegát jehož tělo vytvoříš v kódu a použiješ. Je to proměnná na úrovni
třídy. Platí omezení - žádný out/ref, žádné skoky ven a ani dovnitř. Vhodné pro jednorázové použití. Pro
vícenásobné použij pojmenovanou
- Lambda výrazy. Je to jen syntaxe Anonymních metod. delegate (param) nahradíš param =>. nebo (param1,param2
=>) . Typ není nutné zadávat překladač si ho zjistí.
- Kovariance, kontavariance. Metoda, kterou delegát volá nemusí být schodný s deklarací. Lze volat i
rodičovské třídy.
- Události. Události z pohledu příjemce buttonOne.Click += new EventHandler(Button_Click). Vyvolání události
EventArgs
Řetězce a regulární výrazy
Genericita
- Genericita je definována v CLR. Podobně fungují v c++ šablony, ale potřebuješ zdroják. Zejména pro třídy kolekcí. Lze to udělat přes Object, ale musíš přetypovávat.
- Výkon - nedochází k boxingu. Třída ArrayList umožňuje heterogenní třídy a je to vlastně List<Object>. Lepší je samozřejmě List<T>
Kolekce
LINQ
Správa paměti a ukazatele
Reflexe
Chyby a vyjímky
Návrhové vzory
SOLID
- Single responsibility principe - Každá třída jen jednu zodpovědnost. ()
- Open/Close principe - Funkcionalitu třídy lze rozšířit bez nutnosti její modifikace.
- Liskov substitution principle - Třídy musí být plně nahraditelné svými potomky.
- Interface segregation principle - Používat malá a úzce zaměřená rozhraní.
- Dependency inversion principle - Závislost na abstrakcích, nikoliv na implementacích.
GOF gang Of Four (itnetwork - karia/mat)
Creational patterns (pro vytváření)
- Factory třída k vytváření instancí jiných tříd. Vytvoř formulář, list papíru (A1). Zpravidla vrací rodičovský typ nebo rozhraní. Pokud třída kterou vrací má private konstruktor, tak nevytvoříš třídu jinak než přes konstruktor.
- Singleton - sdílení jedné instance mezi více třídami. Jinými slovy - pro globální přístup k instanci nějaké třídy. Např. s databází. Je vhodné doprogramovat aby byla thread-safe. Ale i tak je to nadoporučované a asi to plně nahradí DI
- Prototype - něco jako Factory, ale klonují se prototypy.
- Builder - pokud je toho moc (třeba parametrů) a nehodí se factory je ideální Builder. Proces generace se pak sestává z částí stavby (základy, přízemí, první patro, střecha). Pak existuje stavbyvedoucí, který celý proces kontroluje přes jednotné rozhraní. To má zpravidla workflow (příprava, začátek, kopeme, betonujeme, stavíme, začištujeme, hotovo). Jeho použití je zřejmé z příkladu:
Person person = Person.builder()
.withName("John Doe")
.ofAge(value)
.build();
Structural patterns (struktury)
- Adapter (Wrapper) - obalíme komponentu naším rozhraním. Nevadí pak že autor komponenty mění rozhraní. Většinou s databází (lze měnit různé výrobce DB) nebo Web služeb/API
- Facade (fasáda) - jednotné logické rozhraní
- Proxy (zástupce) - Remote Proxy. Nějaká funkcionalita je na vzdáleném PC, ale my to odstíníme a lze s tím pracovat jako by byl na vlastním. Virtual proxy. Nějaké zařízení co chceme používat neexistuje, ale my napíšeme simulátor. Protection proxy. K objektu lze přistupovat jen s právy, nebo některé nebezpečné funkce chceme odstínit. Smart Reference. Nějaký často používaný objekt uložíme do paměti a dále ho používáme odsud a né z hlavního objektu.
- Decorator - rozšíření funcionality bez dědění. Vhodné třeba u knihoven. Decorator zachovává původní rozhraní, ale pouze ho rozšiřuje. Např. do každého obrázku chcete vykreslit svoje logo. Rozšíříme knihovnu pro vykreslování. Pokud bychom dědili porušíme principy OOP.
- Flyweight (muší váha)
- Composite - pro práci se stromy
- Bridge - Na rozdíl od adapteru počítá s tím že se mění rozhraní na obou s stranách.
Vzory chování
- Observer (pozorovatel). - Jakým způsobem zpropagovat změnu (třeba jména) do všech metod, které to používají. Každý prvek obsahuje metodu Obnovit a jeden Observer pak projede všechny prvky.
- Strategie - jak měnit metody třeba pro výpočet slevy přímo za běhu aplikace. Teda bez dalších switch.
- Template method - zavádí kostru algoritmu. Třeba rozhraní ZapisHlavicku(), ZapisTelo(), ZapisPaticku()
- State
- Memento - návrhový vzor jak ukládat předchozí stav objektu. UNDO
- Interpreter - překladač. Z jazyka do jazyka
- Mediator - pokud spolu třídy něajk souvisí a to výrazně napřeskáčku je lepší aby komunikovaly přes jednu třídu - Mediator. Např. komunikace s formulářovými prvky. Nebo logger. Ten se pak postará kam co zapisovat.
- Iterartor - jak procházet kolekce IEnumerator
- Chain of responsibility - pomocí handleru se vyřeší nějaký složitý požadavek. Např. přijetí mailu přes metodu přijmi(). Ta volá handler přijmi() a ten zajistí kontrolu spamu, kontrolu příjemce, vyvěšení vlajky že něco přišlo, a uložení. Ale to dělá handler a né ta třída.
Příklady