Příkaz můžeme chápat jako krok v cestě algoritmu. Většinou se provádějí v pořadí, ve kterém jsou v programu zapsány a některé příkazy musejí být ukončeny středníkem. V C# se ovšem vyskytují příkazy, které se takto chovat nemusí. Říkáme jim skokové příkazy. Podrobněji vše probereme níže.
V této sekci si rozebereme základní příkazy jazyka.
Blok je typ příkazu, který může, ale nemusí, reprezentovat další množinu příkazů. Blok označíme stejně jako například v Javě symboly { a }. Dovnitř bloku můžeme vložit další příkazy, popřípadě další blok. Pokud blok neobsahuje žádné příkazy, nazývá se prázdný příkaz. Příklad:
// priklad bloku { Console.WriteLine("Outer block"); //toto je vnoreny blok { string text = "Inner block"; Console.WriteLine(text); } } |
Mohou nastat situace, kdy na někjakém místě programu jazyk C# vyžaduje přítomnost příkazu, ale my nechceme provádět žádný příkaz. Proto v C# existují i prázdné příkazy.
Jak jsme si uvedli v předchozím odstavci, prázdný příkaz můžeme vyjádřit pomocí dvou složených závorek, které nic neobsahují {}. Další možnost, jak vyjádřit prázdný příkaz, je použitím středníku ;. To nám zaručí, že program na daném místě nebude nic provádět.
Příklad, kdy využijeme prázdných příkazů - chceme se dostat v řetězci na první znak, který není mezera (tedy vypustíme z úvodu řetězce mezery):
int i=-1; while((retezec[++i] == ' ') && (i < retezec.Length)) ; // nebo {} |
Podmíněný příkaz if má stejnou syntaxi jako v ostatních programovacích jazycích. Pro ty z vás, kteří se s programováním přece jen nesetkali, uvedeme jeho popis.
Příkaz if má dvě podoby - úplné if a neúplné if.
Úplné if je tvořeno:
if (podminka) { ... } // provede se telo prikazu {}, pokud podminka plati (ma hodnotu true) else { ... } // provede se telo prikazu {}, pokud podminka neplati (false) |
Neúplné if je tvořeno podobně jako předchozí úplné if, s tím rozdílem, že neuvedeme situaci, kdy podmínka neplatí:
if (podminka) { ... } // provede se telo prikazu {}, pokud podminka plati |
Místo bloku (složeného příkazu) lze použít jednoduchý příkaz. V tom případě za příkazem musíme napsat i středník.
Příkaz if (jak úplný, tak i neúplný) můžeme také vnořit do předchozího příkazu if a vytvářet tak složité konstrukce na testování i různých podmínek. Objeví se zde ale problém v přehlednosti kódu. Proto je výhodné psát program co možná nejlépe strukturovaně, odsazovat jednotlivé části kódu, bloky, abychom se v nich vyznali buď my nebo ti, kteří po nás kód budou číst. V prostředí Microsoft Visual Studio .Net se o odsazování většinou starat nemusíme, nicméně někdy se stane, že vkládáme část kódu (např. pomocí Copy-Paste), která se nezformátuje správně.
Příkaz if je přehledný, pokud testujeme dvě podmínky. Pak se stává nepřehledným. Příkaz switch používáme pro testování více vstupních podmínek. Jeho zápis je ve tvaru:
switch (vyraz) { case hodnota1 : prikazy; break; case hodnota2 : prikazy; break; ... default : prikazy; } |
kde vyraz značí výraz, který chceme testovat. Musí nabývat pouze hodnot celočíselných, char, výčtových nebo string. case hodnota1, case hodnota2... jsou návěští, pro které chceme, aby příkaz switch reagoval a default je návěští, kam se switch dostane, pokud se mezi konstantami hodnota1, hodnota2... nenajde ani jedna, která by odpovídala hodnotě výrazu. Návěští default není povinné, takže pokud switch neobsahuje návěští default a nenajde konstantu, která by odpovídala hodnotě výrazu, neprovede se nic.
Cykly také nazýváme smyčkami nebo iteračními příkazy. Jedná se o příkazy, které provádějí cyklicky jeden nebo několik příkazů. Většinou počet opakování závisí na podmínce cyklu (opakování).
while (podminka) { ... } |
Cyklus while se provádí tak dlouho, dokud podmínka podminka nabývá hodnoty true. Pokud podmínka nabude hodnoty false, cyklus skončí (tělo cyklu se přeskočí). U toho cyklu se může stát, že se neprovede ani jednou, neboť pomínka se vyhodnocuje před tělem cyklu.
Cyklus do-while je podobný jako cyklus while s tím rozdílem, že podmínka se vyhodnocuje až po průchodu těla cyklu. Tedy tělo cyklu se provede pokaždé alespoň jednou.
Příkaz for se používá asi nejčastěji z příkazů pro cykly. Je užitečný jak pro procházení indexů pole nebo jednoduchého opakování na základě změny hodnoty proměnné. Nepoužívá se ale nutně pouze v těchto případech.
for(promenna;podminka;zmena_promenne) { ... } |
Proměnná promenna určuje počáteční hodnotu proměnné v cyklu. Proměnná může být v tomto místě i deklarována a inicializována. Podmínka omezuje proměnnou, tedy do jaké hodnoty proměnné se má ještě tělo cyklu vykonávat. Jako poslední se definuje, na jakém základě se bude proměnná měnit (zmena_promenne). Následující příklad bude vypisovat na obrazovku hodnotu proměnné od 0 do 9 pokaždé na nový řádek:
for(int i = 0; i < 10; i++) System.Console.WriteLine(i); |
Cyklus for ale může fungovat i bez udání proměnné, podmínky a změny proměnné. Poté se tento cyklus bude provádět donekonečna. Aby se takto vytvořený cyklus dal nějak zastavit, pak se používají (kromě CTRL+C již za běhu programu) příkazy break, return, goto v jeho těle.
Představme si nějaký kontejner (nyní nemám na mysli velkou nádobu, do které se vyhazuje odpad), který obsahuje různé objekty. My chceme pro každý z objektů zjistit typ tohoto objektu. Samozřejmě to můžeme provést několika způsoby, například příkazem for, ale zde se dobře hodí příkaz foreach, který prochází všechny prvky kontejneru:
using System; using System.Collections; ... ArrayList a = new ArrayList(); a.Add(1); a.Add("string"); a.Add(new object); foreach(object obj in pole) Console.WriteLine(obj.GetType()); ... |
Program nám následně vypíše:
System.Int32 System.String System.Object
Příkazy, které způsobí, že program přeruší přirozenou posloupnost plnění příkazů (tedy za sebou, jak jsou napsány), se nazývají skokové příkazy. Tehdy program přejde na jiné místo v programu rozdílné od této přirozené posloupnosti.
Příkaz break způsobí, že program vyskočí z nejbližšího cyklu, ve kterém se právě nachází. Kromě cyklů se break smí použít i v příkazu switch, jak jsme uvedli výše. V cyklu se používá následovně:
using System.Collections; ... ArrayList a = new ArrayList(); a.Add(3); a.Add("string"); a.Add(new object()); foreach(object o in a) if(o.GetType().Name == "String") break; ... |
v cyklu foreach postupně zjištujeme, zda typ objektu je instancí třídy String. Pokud ano, příkaz break způsobí ukončení cyklu. Zde použitá metoda GetType() obvykle vrací kromě názvu typu také jmenný prostor (popřípadě prostory, pokud je vnořený), kam typ náleží. Vlastnost Name nám vrátí pouze název typu, což je výhodné. Jinak bychom museli zjištovat, v kterém jmenném prostoru se daný typ nachází.
Lze použít pouze v cyklech. Pokud použijeme tento příkaz, způsobí to, že přeskočíme zbytek těla cyklu a začneme novou iteraci (další opakování cyklu).
int sumaSude = 0; for(int i=0; i<100; i++) { if(i % 2 != 0) continue; else sumaSude += i; } |
Pokud je i liché číslo, cyklus začne novou iteraci. Pokud je i sudé, přičte se k proměnné sumaSude.
Tento příkaz se většinou v novějších programovacích jazycích nesetkával s oblibou. Platilo, že čím více příkazů goto, tím horší je kvalita programu. Jazyk C# tento příkaz obsahuje, ale snaží se zabránit jeho zneužití, např. nelze skočit dovnitř blokového příkazu. Tento příkaz je doporučován pro použití v příkaze switch nebo pro předání řízení do vnějšího bloku, ale ostatní použití není nepovolené.
... // tato konstrukce neni povolena goto UVNITR_CYKLU; for(int i=0; i<100; i++) { UVNITR_CYKLU : System.Console.WriteLine(i); } ... // takto prikaz goto pouzit lze for(int i=0; i<100; i++) { if(i == 34) goto VEN; else ... } VEN : ; ... |
Tímto příkazem se vrací řízení volající funkci. Příkaz return může být spojen i s hodnotou, pokud metoda, která return použije, má návratovou hodnotu jinou než void.
... long mocnina(int zaklad, int mocnina) { long vysledek = 1; for(int i = 1; i <= mocnina; i++) vysledek *= zaklad; return vysledek; } ... |
Pokud používáme konverzi typů, někdy se stane, že při konverzi z jednoho typu na druhý si chceme být jisti, že převod proběhl úspěšně. C# pro ten případ používá příkaz checked. Když potom chceme ověřit správnost konverze, uvedeme naši konverzi v kontrolovaném bloku příkazu checked.
uint iSmall = 3; byte bSmall; uint i = 412; byte b = 0; ... // standardne je kontrola nastavena jako unchecked bSmall = (byte)iSmall; b = (byte)i; System.Console.WriteLine(b+", "+bSmall); // nic se nemeni bSmall = unchecked((byte)iSmall); b = unchecked((byte)i); System.Console.WriteLine(b+", "+bSmall); // zatim vse v poradku bSmall = unchecked((byte)iSmall); // zde pri konverzi vyskoci vyjimka b = checked((byte)i); System.Console.WriteLine(b+", "+bSmall); |
Jelikož kontrola správnosti konverze má určitý vliv na výkonnost, nedoporučuje se ji používat u široce distribuovaného softwaru.
Je to ale užitečný pomocník pro kontrolu, zda dané přetypování proběhlo úspěšně. Proto se dá použít při kompilaci přepínač /checked, který způsobí, že všechny konverze typů se budou kontrolovat. Poté je ale třeba všechny konverze, které kontrolovat nechceme, označit pomocí příkazu unchecked.
Příkaz throw slouží k vyvolání výjimky. Uplatní se tehdy, pokud chceme ošetřit nějakou část kódu. V případě, kdy se vyskytnou jiné podmínky v programu, než jsme si představovali, můžeme pomocí throw vyvolat nějakou výjimku. Příklad:
... // deleni dvou realnych cisel double vydel(double delenec, double delitel) { if(delitel == 0) throw new DivideByZeroException("Nulou nelze delit!"); else return(delenec / delitel); } ... |