Množina operátorů v jazyce C# je až na pár výjimek identická s operátory v jiných programovacích jazycích.
Definování bloku unsafe se explicitně zříkáme bezpečnostních kontrol prostředí .NET. Blok je definován pomocí klíčového slova unsafe a složenými závorkami. Je nutné překladači povolit unsafe bloky.
Třídy
Třídou se v C# rozumí programová datová struktura. Třída může obsahovat tyto členy:
1. položky (field) – členské proměnné, udržují stav objektu
2. metody – jde o funkce, které implementují služby objektem poskytované. Každá metoda má návratovou hodnotu, pokud nic nevrací, je označena klíčovým slovem void. V jazyce C# lze přetěžovat metody. Přetížené metody se musí lišit v počtu parametrů, v typu parametrů nebo v obojím. Výjimečná metoda je statická metoda s názvem Main. Právě pomocí této metody je projekt spouštěn. Je-li v projektu definováno více metod Main, je nutné při kompilaci zadat jako parametr jméno jedné třídy z těchto tříd. Metoda Main této třídy je pak spuštěna. Každá třída může obsahovat maximálně jednu metodu Main;
3. vlastnost (property) – je také označována za chytrou položku. Navenek vypadají jako položky, ale umí kontrolovat přístup k jednotlivým datům;
4. indexer – u některých tříd je výhodné definovat operátor []. Indexer je speciální metoda, která umožňuje aby se daný objekt choval jako pole;
5. operátory – v jazyce C# máme možnost definovat množinu operátorů sloužících pro manipulaci s jejími objekty;
6. událost (event) – jejím účelem je upozorňovat na změny, které nastaly např. v položkách tříd.
U jednotlivých členů třídy můžeme použít modifikátory přístupu. Modifikátor je nutné aplikovat na každého člena zvlášť. Jeho uvedení není povinné, implicitní hodnota je private. Možné modifikátory jsou:
1. public – člen označený tímto modifikátorem je dostupné bez omezení;
2. private – člen je přístupny pouze členům stejné třídy;
3. protected – přistupovat k takovému členu můžeme uvnitř vlastní třídy a ve všech třídách, pro které je třída základem;
4. internal – člen je přístupný všem v rámci jedné assembly.
Dalším možným modifikátorem je modifikátor static, pomocí něj lze deklarovat, že je daný člen třídy statický. Uvnitř nestatických metod třídy můžeme použít klíčové slovo this, to reprezentuje referenci objektu na sebe sama.
Metody a parametry
Parametry jsou obvykle předávány do metody hodnotou. Funkce získá kopii skutečných parametrů a jakékoliv modifikace uvnitř těla metody se nepromítnou zpět. V jazyce C# máme dvě řešení.
1. Předání parametru odkazem. Metoda si nevytváří vlastní kopii, nýbrž přímo modifikuje proměnnou, která ji byla předána. Takovéto parametry označíme klíčovým slovem ref. Předávané parametry musí být inicializovány.
2. Definovat parametry jako výstupní. Takové parametry označíme klíčovým slovem out. Parametry pak přenášejí své hodnoty směrem ven z metody. Hlavním rozdílem oproti předávání parametrů odkazem je, že předané proměnné nemusí být inicializovány před voláním metody. Uvnitř těla funkce je brán parametr jako neinicalizovaný.
Ukázka kódu
class Test
{
public void Swap(ref int a, ref int b){
int tmp;
tmp=a;
a=b;
b=tmp;
}
public void GetXY(Point somePoint,out int x, out int y){
x=somePoint.GetX();
y=somePoint.GetY();
}
public static void Main()
{
int a=5,b=3;
Swap(ref a,ref b);
GetXY(new Point(1,2),out a,out b);
}
}
V jazyce C# musí být každá funkce metodou třídy. Pokud potřebujeme samostatné funkce, můžeme vytvořit statické metody třídy. Takové jsou např. elementání funkce třídy System.Math nebo metoda WriteLine třídy System.Console:
Console.WriteLine("sin({0})={1}",x,Math.Sin(x));
Metoda s proměnným počtem parametrů
Chceme-li definovat metodu s proměnným počtem parametrů, využijeme klíčové slovo params. To musíme uvést před posledním parametrem. Typ tohoto parametru musí být pole.
public void someMethod(params object[] p); //deklarace metody s proměnným počtem parametrů
Konstruktory a destruktory
Konstruktor nevrací žádnou hodnotu (ani void). Každá třída má definovaný implicitně konstruktor bez parametrů a s prázdným tělem. Každý objekt by pak měl být vytvořen pomocí operátoru new. Jiným typem konstruktoru je tzv. statický konstruktor. Pomocí něj lze inicializovat statické položky. Jiné položky pomocí tohoto typu konstruktoru inicializovat nelze. Tento konstruktor nesmí mít žádné parametry a je vyvolán ještě před vytvořením prvního objektu. Pro statické konstruktory dále platí, že jsou spouštěny v náhodném pořadí. Nelze se tedy v jednom spoléhat na druhý.
class Point
{
static short dimension;
short x=0
private short y=0;
public Point()
{
}
public Point(short nx, short ny)
{
x=nx;
y=ny;
}
static Point()
{ //statický konstruktor
dimension=2;
}
static void Main()
{
Point a = new Point();
Point b = new Point(1,2);
}
}
Chceme-li zavolat konstruktor stejné třídy, můžeme to udělat pomocí klíčového slova this. Syntaxi demonstruje následující příklad.
public Point(Point p):this (p.GetX(), p.GetY())
{
{
Destruktor má název začínající tildou (~) následovaný jménem třídy. Od konstruktoru se liší tím, že nesmí mít žádné formální parametry a nemůže být přetížen. Pokud to není nutné, nemusí být definován.
Dědičnost a polymorfismus
Představuje jeden ze základních rysů objektově orientovaného programování. Dědění tříd umožňuje definovat nové třídy na základě tříd, které již existují. Třídy, od kterých odvozujeme nové třídy jsou nazývány rodičovské třídy. Odvozené třídy jsou označovány jako potomci nebo dceřiné třídy. Skupiny provázaných tříd (vztahem předek-potomek) jsou nazývány dědické hierarchie.
Odvozená třída "zdědí" vlastnosti svých předků - bude obsahovat všechny nestatické datové složky svých předků a bude moci používat jejich metody, typy a statické složky (pokud jí to dovolí přístupová práva).
Dědění se využívá v OOP pro vyjádření specifikace: Předek popisuje abstraktnější pojem, zatím co potomek popisuje konkrétnější, přesněji vymezený pojem
Jazyk C# definuje pouze jednoduchou dědičnost. Dědičnost v definici třídy vyjádříme dvojtečkou uvedenou za jménem třídy a názvem základní třídy. Pro metody odvozené třídy pak platí:
- chceme-li předefinovat veřejnou metodu třídy kterou dědíme, musíme použít klíčové slovo new. V tomto případě záleží na typu reference, jaká metoda se zavolá;
- chceme-li realizovat polymorfismus, použijeme virtuální metody. Postup je následující: metodu základní třídy označíme jako virtuální (klíčové slovo virtual) a metodu v odvozené třídě označíme klíčovým slovem override (má se chovat polymorfně).
class A
{
public void SomeMethod()
{
}
public virtual void AnotherMethod()
{
}
}
class B : A
{
public new void SomeMethod()
{
//původní metoda je překryta
}
public override void AnotherMethod()
{
}
}
class Run
{
static void Main()
{
A a=new B();
a.SomeMethod(); //spustí původní metodu třídy A
a.AnotherMethod(); //spustí metodu třídy B
}
}
Konstruktory v odvozených třídách
Chceme-li volat konstruktor základní třídy v odvozené třídě, můžeme k tomu využít klíčové slovo base. Syntaxi demonstruje následující příklad:
Ukázka kódu
public SomeName(…):base(…){ … }
Pole
Pole chápeme jako množinu proměnných stejného datového typu. S takovým polem pak zacházíme jako s celkem. Na jednotlivé prvky pole (proměnné) se můžeme odkazovat pomocí jejich indexů pole a poté s nimi pracovat jako s obyčejnými proměnnými. Každý počáteční prvek pole v C# má index 0, pokud tedy máme pole délky N, index posledního prvku bude N-1.
Deklarace pole
V C# existují dva způsoby, jak deklarovat pole. První ze způsobů více naznačuje objektovost polí. Ten si ukážeme jen "ve zkratce", více se budeme zabývat druhým, klasickým a určitě i praktičtějším způsobem.
Jazyk C# umožňuje vytvořit instanci pole pomocí statické metody
System.Array.CreateInstance(). Tento způsob více odpovídá objektové charakteristice tvorby objektů.
Ukázka kódu
using System; ... Array pole = Array.CreateInstance(typeof(int), 4);
Vytvořili jsme instanci třídy Array typu int se čtyřmi prvky. Pokud budeme toto pole chtít naplnit, nemůžeme již k jednotlivým prvkům přistupovat pomocí indexů, jako jsme byli zvyklí u běžných polí. Je třeba k těmto prvkům přistupovat pomocí metod SetValue() a GetValue().
Ukázka kódu
... pole.SetValue(3, 0); // na nultou pozici pole vlozime cislo 3 Console.WriteLine(pole.GetValue(0)); // vytiskneme 0. prvek pole ...
Stejným způsobem, ale i s možností přistupovat k jednotlivým prvkům pole pomocí indexů, můžeme tehdy, pokud vytvoříme pole druhou (následující) konstrukcí. První způsob tedy opustíme.
Pro jednorozměrná pole v jazyce C# platí deklarace:
typ[] nazev_pole;
Vícerozměrná pole
Pokud chceme deklarovat vícerozměrné pravidelné pole, píšeme nejprve typ pole, následují hranaté závorky, do kterých napíšeme pouze čárky podle toho, kolikarozměrné pole chceme používat. Příklad: Deklarace 2-rozměrného pole s názvem pole typu int
Ukázka kódu
int[,] pole = new int[2,2] { {2, 1}, {4, 3} };
Vícerozměrná nepravidelná pole
V jazyce C# lze používat i nepravidelná pole. Nepravidelná pole se vyznačují různou délkou jednotlivých "řádků" pole. Pokud například chceme vytvořit pole, které má v prvním řádku 3 prvky a v druhém 2 prvky, provedeme to následovně:
Ukázka kódu
int[][] pole; pole = new int[2]; pole[0] = new int[3]; pole[1] = new int[2];
Přístup k jednotlivým prvkům pole se pak provádí následovně: pole[0][0] nám vrátí hodnotu prvku v první řadě a prvním sloupci.
Kopírování polí
Místo obvykle používaného cyklu pro kopírování pole x do pole y:
Ukázka kódu
for(int i=0; i<=x.Length; i++) y[i] = x[i];
lze použít metodu CopyTo() dostupnou všem polím
Ukázka kódu
CopyTo() x.CopyTo(y,0);
První parametr udává cílové pole, do kterého se má kopírovat druhý parametr udává počáteční index, na který se bude ukládat. Pokud cílové pole od daného počátečního indexu nebude dostatečně dlouhé, vyvolá se výjimka.
Podmíněné příkazy
Příkaz if
Má stejnou syntaxi jako v ostatních programovacích jazycích.
if (podmínka)
statement(s)
else
statement(s)
Více příkazů se musí uzavřít do bloku {}. Pro jeden příkaz nemusíme požívat závorky.
Příkaz switch...case
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;
}
Cykly
Cyklus while
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
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.
Cyklus for
for(int i = 0; i < 10; i++) System.Console.WriteLine(i);
Cyklus foreach
Ideální k procházení všech prvků 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());
...
Skokové příkazy
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
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.
Příkaz continue
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).
Příkaz goto
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é.
Příkaz return
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.
Příkazy checked a unchecked
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.
Příkaz throw
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.