Referenční typy - třída

Stránky: Moodle ZČU
Kurz: KPV/TI Technická informatika ve strojírenství - šablona
Kniha: Referenční typy - třída
Vytiskl(a): Nepřihlášený host
Datum: neděle, 8. listopadu 2026, 16.21

1. Třída

Abychom pochopili rozdíl mezi hodnotovým a referenčním datovým typem, je nejprve objasnit pojem třída (ta je referenčního typu).

Jazyk C# je objektově orientovaný jazyk (dále budeme využívat zkratku „OOP“ – anglicky „Object Oriented Programming“ - objektově orientované programování). Když jsme poprvé analyzovali základní program vygenerovaný pro konzoli, náš Program.cs definoval třídu Program a metodu Main, která náležela této třídě (anglicky „Class“). Třída – klíčové slovo class - je kořenem slova klasifikace anglicky „Classification“. V C# je veškerý spustitelný kód definován v rámci metody a všechny metody musí patřit do třídy nebo struktury.

Microsoft .NET Framework obsahuje tisíce tříd, z nichž už jsme si některé vyzkoušeli např. Console a Exception. Třídy poskytují mechanismus pro modelování tzv. entit (anglicky „Entity“), které odrážejí prvky reálného světa, ale i abstraktní věci. Součástí návrhu systému je vždy analýza, jejímž cílem je vymezit důležité entity, které jsou ve vztahu s procesy, které daný systém implementuje a správně definovat data, která mají tyto entity obsahovat a jaké funkce mají provádět. Informace, které třída uchovává, jsou ukládány ve formě datových složek (anglicky "Fields" - nazývaných též atributy) a operace jsou implementovány jako metody (anglicky "Methods"). [6]

Když definujeme třídu, musíme systematicky uspořádat informace a chování do smysluplné entity – jedná se tedy o akt klasifikace, který v podstatě děláme každý a nejen programátoři. Ukažme klasifikaci na příkladu auta. Automobily mají společné vlastnosti, můžeme je řídit, zastavit, rozjet apod – představme si tyto vlastnosti jako metody. Mají také společné atributy – kola, volant, motor apod. Vidíme, že auta mají společné prvky, lze tedy odvodit jistý předpis, který je společný pro podstatnou většinu aut – třída. Třída je předpisem pro vytvoření objektu. Pokud je objekt vytvořen na základě definované třídy, lze ho také obecně nazvat tzv. instancí příslušné třídy. Instance je vytvářena za běhu programu. Instance má stejné rozhraní jako třída, podle které je vytvořena. Jednotlivé objekty třídy se od sebe navzájem liší svými atributy. Jako příklad nám poslouží dva objekty třídy Auto jakými jsou např. autoOctavia a autoFord. Tato dvě auta (objekty) se budou se lišit svými atributy, tzn., že mají různé parametry např. SPZ, typ, objem [cm3] a výkon [kW] motoru, spotřeba [l/100 km], cena [Kč], rok výroby apod. Tyto atributy jsou uloženy pomocí tzv. datových složek, které využíváme pro uložení informací např. u objektu autoOctavia budou nastaveny parametry auta, tj. atributy objektu jako SPZ = "4P49462"; typMotoru = "TDI"; objemMotoru = 1.9; vykonMotoru = 81, spotrebaMotoru = 5, atd. Asi cítíme, že to jiné nastavení parametrů auta můžeme udělat i u objektuFord.

Další důležitou vlastností objektově orientovaného programování je zapouzdření (anglicky "Encapsulation"). Atributy a metody objektu tvoří nedělitelný celek a vzájemně se ovlivňují. Díky zapouzdření může objekt své metody a atributy skrýt před okolím. Představme si, že bychom u automobilu měli volně přístupnou metodu vypusť nádrž. Asi bychom nechtěli, aby jiný programátor nám omylem vypustil právě natankované auto. Členy přístupné okolí se nazývají rozhraní (anglicky "Interface") objektu.

V programování jsme se již s něčím podobným setkali. Využívali jsme proměnné, které byly jistého datového typu a pomocí metod jsme mohli ovlivňovat hodnoty uložené v těchto proměnných. Objekt reprezentuje složitější proměnnou složitějšího datového typu – třídy (v našem příkladu Auto). Když jsme potřebovali vytvořit proměnnou, deklarovali jsme ji. Když potřebujeme vytvořit objekt, použijeme konstruktor (v našem příkladu auta si můžeme představit konstruktor jako metodu, která nastaví parametry auta např. typMotoru = "TDI"; objemMotoru = 1.9; vykonMotoru = 81). Když jsme potřebovali zacházet s proměnnými, použili jsme metody. K zacházení s jednotlivými objekty (popřípadě jeho datovými složkami) budeme používat také metody (v našem příkladu metoda Zastav, Rozjed, Zpomal atd.). Pokud mluvíme o objektovém programu, skládá se pouze z objektů, kde si mezi sebou objekty navzájem posílají zprávy, tzn., že volají (spouštějí) své metody (v našem případě auto může komunikovat s jiným autem např. předání informací o stavu na vozovce).



2. Zapouzdření

Důležitým principem používaným v OOP je princip zapouzdření (anglicky „Encapstulation“), tzn., že se program využívající nějakou třídu se nemá starat o to, jak tato třída interně funguje. Program pouze vytvoří instanci této třídy a poté volá její metody. Třída si někdy musí uchovávat informace o jejím interním stavu, které jsou nutné pro provádění metod. Takové informace jsou však také před programem skryty. Vidíme, že zapouzdření představuje „určité skrývání“ vlastních informací před vnějškem.

Zapouzdření má dva hlavní účely:

  • Kombinovat metody a data (ve formě datové složky) uvnitř třídy
  • Kontrolovat přístupnost metod a dat – kontrola použití třídy [6]


3. Deklarace třídy

Zjednodušeně můžeme deklaraci třídy popsat následujícím způsobem:

modifikátorPřístupu class identifikátorTřídy předekARozhraní
{
	těloTřídy
} 

kde:

  • class - klíčové slovo uvozující identifikátor třídy (název třídy)

Další atributy deklarace budou popsány v následujících podkapitolách.



3.1. Modifikátor přístupu třídy

Spojení „určité skrývání“ vlastních informací třídy před vnějškem bylo použito záměrně (např. u našeho příkladu auto, bychom nechtěli, aby po natankování plné nádrže někdo zavolal metodu vypustNadrz). U některých datových složek můžeme specifikovat přístupová práva tzv. modifikátor přístupu (anglicky „Access Modifiers“). Modifikátor přístupu specifikovaný pro třídu lze rozdělit do dvou základní kategorií:

Modifikátor přístupu značí přístupová práva ke třídě, která mohou využívat následující klíčová slova:

  • public – veřejně přístupná třída – můžeme ji využívat a vytvářet její instance, volat její metody apod. - kdokoliv ve kterékoliv části programu (pokud to dovolí práva v datových složkách), v němž jsme ji deklarovali a v jakémkoliv jiném programu, který obsahuje odkaz na seskupení (viz kapitola Seskupení), jež tuto třídu obsahuje
  • internal – třídu lze použít pouze v rámci aktuálního programu. Jestliže nevyužijeme ani public a ani internal, bude se třída chovat jako bychom použili internal
  • abstract – abstraktní třída – nelze od ní vytvořit instanci. Abstraktní třída typicky shrnuje společné vlastnosti svých potomků
  • sealed – zapečetěná třída – nelze od ní odvozovat potomky. Je v jistém smyslu opakem klíčového slova abstract. Abstraktní třída nemůže být zapečetěná. Lze uvést pouze jedno klíčové slovo, buď abstract nebo sealed [3]

3.2. Identifikátor třídy

Identifikátor třídy, tedy název třídy (včetně konstruktoru třídy užívaného pro vznik instance třídy), budeme uvozovat velkým písmenem. Pokud je název složen z více slov, použijme velbloudí notaci („CamelCase“) – každé slovo začíná velkým písmenem. Pro identifikátor třídy platí stejná pravidla jako pro obecný identifikátor – viz kapitola Identifikátor.


3.3. Předek a rozhraní

Vzhledem k tomu, že jsem teprve v začátcích popisu funkcionalit třídy, berme následující specifikace předka a rozhraní třídy prozatím jako doplňující informaci. U specifikace se jedná o určení předka a implementovaných rozhraní pro danou třídu. Tato specifikace může mít tvar:

: jménoBázovétřídy

: jménoBázovétřídy, seznamRozhraní

: seznamRozhraní

kde:

  • jménoBázovétřídy - identifikátor třídy, kterou chceme použít jako předka právě deklarované třídy. Je-li to nutné, připojíme k identifikátoru bázové třídy kvalifikaci jménem prostoru jmen. Pokud specifikaci předka vynecháme, doplní si překladač jako předka třídu object, která je společným předkem všech tříd v C#
  • seznamRozhraní - představuje jména implementovaných rozhraní oddělená čárkami [3]


3.4. Tělo třídy

Tělo třídy je uzavřeno ve složených závorkách. Tělo obsahuje deklaraci datových složek, metod, vlastností atd. Pro deklarace, které tvoří tělo třídy, budeme používat souhrnné označení složky. Pro každou ze složek třídy, tj. pro datové složky i metody musíme určit přístupová práva – modifikátory přístupu. Po definování úrovně přístupu pojmenujme datovou složku „S“ ve třídě „T“. V jazyku C# rozlišuje u složek následující modifikátory přístupu:

  • public – tzv. veřejně přístupná datová složka S je dostupná všude, kde lze použít třídu T. O veřejně přístupných metodách hovoříme také jako o rozhraní třídy
  • protected internal – složka S je dostupná z T a ze všech tříd, které jsou potomkem třídy T
  • protected – tzv. chráněná složka S je dostupná pouze ve třídě T anebo u jejích potomků
  • internal – tzv. interní složka S je dostupná pouze ze seskupení (například z nějaké dynamické knihovny – viz kapitola Seskupení)
  • private – tzv. soukromá složka S je dostupná pouze uvnitř třídy T. Tento modifikátor přístupu je implicitní, tzn., že pokud neuvedeme žádný modifikátor přístupu, bude brán přístup jako soukromý

Identifikátory složek, které jsou public budeme uvozovat na začátku velkým písmenem (tento přístup je v angličtině označován jako „PascalCase“, protože byl poprvé použit v jazyce Pascal). Ostatní složky, které nejsou public budeme označovat malým písmenem. 

V následující tabule jsou zobrazena přístupová práva u složek pro jednotlivé modifikátory přístupu - viz Tabulka 1. Slovo Ano znamená, že složka s odpovídajícím modifikátorem je dostupná v rámci téže třídy, v tomtéž seskupení, téhož potomka atd. 

Modifikátor přístupu

Třída

Seskupení

Potomci

Ostatní

public

Ano

Ano

Ano

Ano

protected internal

Ano

Ano

Ano

Ne

protected

Ano

Ne

Ano

Ne

internal

Ano

Ano

Ne

Ne

private

Ano

Ne

Ne

Ne

Tabulka 1: Dostupnost složky v rámci daného modifikátoru přístupu [3]


4. Statická třída

Další vlastností jazyka C # je možnost deklarovat třídu jako statickou. Statická třída může obsahovat pouze statické složky (všechny objekty, které vytvoříte pomocí této třídy, sdílejí jednu kopii těchto složek). Účelem statické třídy je pouze držet užitkové metody a datové složky. Statická třída nemůže obsahovat žádná data nebo metody instance a nemá smysl pokusit se vytvářet instance statické třídy pomocí operátoru new (pokud to zkusíme, kompilátor ohlásí chybu). Pokud potřebujeme provést jakoukoli inicializaci, statická třída může mít výchozí konstruktor. Ten ale musí být deklarován jako statický. Jakékoli jiné typy konstruktoru kompilátor ohlásí jako nepovolené. [6]

Pokud budeme volat statickou datovou složku, nebo statickou metodu, musíme vždy uvádět jméno statické třídy, které tyto složky náleží (vzpomeňte si, že když jsme deklarovali nějakou metodu a volali jsme ji v hlavní statické metodě Main, musela být tato metoda také statická). Pokud nechceme pokaždé vypisovat název statické třídy, můžeme do jmenného prostoru uvést klíčové slovo using a static a definovat jmenný prostor, ve kterém se statická třída nachází. Pomocí tečkové notace vybereme statickou třídu, na níž se chceme odkazovat.

Pokud je používáno příliš statických tříd definovaných ve jmenném prostoru pomocí using, usnadní nám to psaní kódu, ale na druhou stranu je těžké spravovat takový kód. Není totiž jisté, která metoda do které třídy patří, a to může být problémem při jejich správě.


Ilustrativní příklad StatickaMetodaJinaTrida
Program StatickaMetodaJinaTrida
  • Popis: Deklarace dvou statických tříd, použití jmenného prostoru se statickou třídou
  • Zadání: Deklarujte nestatickou třídu Trida, která bude obsahovat hlavní metodu Main ve které budete volat statickou metodu StatickaMetoda z jiné statické třídy StatickaTrida. StatickaMetoda bude pouze obsahovat výpis textu "Nyní probíhá statická metoda v jiné statické třídě". Obě třídy jsou deklarovány ve společném jmenném prostoru StatickaMetodaJinaTrida
  • Řešení: Bude postupně probráno v následujícím textu

V následujícím kódu vidíme, volání statické metody jiné statické třídy z hlavní statické metody Main určité třídy – viz Kód 1. Pokud bychom neuvedli odkaz na statickou třídu ve jmenném prostoru, museli bychom u prvního příkazu statické metody Main museli před statickou metodu StatickaMetoda uvést název statické třídy, tj. StatickaTrida.Metoda() ve které je metoda umístěna. Tím, že jsme ve jmenném prostoru definovali using static StatickaMetodaJinaTrida.StatickaTrida; nemusíme u volání metodu StatickaMetoda vypisovat třídu, které patří. 

using System;
//Použití jmenného prostoru, kde je deklarována statická třída
using static StatickaMetodaJinaTrida.StatickaTrida;
 
namespace StatickaMetodaJinaTrida
{
    class Trida
    {
        static void Main(string[] args)
        {
            //Volání statické metody jiné statické třídy
            StatickaMetoda();
            //Čekání na stisk klávesy -> ukončení programu
            Console.ReadKey();
        }
    }
 
 
    //Deklarace statické třídy
    static class StatickaTrida
    {
        //Deklarace veřejné statické metody jiné třídy
        public static void StatickaMetoda()
        {
            //Výpis
            Console.WriteLine("Nyní probíhá statická metoda v jiné statické třídě");
        }
    }
}

Kód 1: Příklad volání statické metody statické třídy v jiné nestatické třídě – uvedení použití statické třídy ve jmenném prostoru

Na výpisu v konzole vidíme, že v rámci metody Main proběhlo volání statické metody jiné statické třídy – viz Výstup programu - Kód 1.

Nyní probíhá statická metoda v jiné statické třídě

Výstup programu - Kód 1: Ukázka výsledku volání statické metody statické třídy v jiné nestatické třídě


5. Datové složky

Ve třídě můžeme použít dvě základní skupiny datových složek (anglicky „Fields“):

  • Statické – uvozené klíčovým slovem static
  • Nestatické – ostatní datové složky, tj. neuvozené klíčovým slovem static

Oba tyto typy datových složek mohou být uvozeny klíčovým slovem:

  • const - konstantní, tj. hodnota datové složky je inicializována pouze v rámci deklarace, hodnotu nikde v kódu již nelze měnit 
  • readonly – pouze ke čtení, tj. hodnotu takové složky lze inicializovat buď v deklaraci, nebo v konstruktoru. Pak už nelze hodnotu v kódu nikde měnit

5.1. Nestatické datové složky

Obecná syntaxe nestatické datové složky může vypadat následovně:

modifikátorPřístupu modifConstRead datovýTyp identifikátor;

modifikátorPřístupu modifConstRead datovýTyp identifikátor = inicializace;

kde:

  • modifikátorPřístupu - specifikuje přístupová práva k datové složce pomocí některé z modifikátoru přístupu
  • modifConstRead - značí buď použití klíčového slova const nebo readonly
  • Identifikátor - značí identifikátor datové složky. Lze také využít druhou variantu, kde použijeme inicializaci datové složky přiřazením počáteční hodnoty. inicializace proběhne bezprostředně po vytvoření instance třídy, ještě před voláním konstruktoru. Pokud ji neuvedeme, bude inicializovaná hodnota datové složky záviset na jejím datovém typu – viz Tabulka 1.


Datový typ

Výchozí hodnota

sbyte, byte, short, ushort, int, uint, long, ulong

0

char

'\x0000'

float

0.0f

double

0.0d

decimal

0.0m

bool

false

object

null

string

null

Tabulka 1: Výchozí hodnoty podle datového typu datové složky [12]


Ilustrativní příklad AutoNestatickeDatoveSlozky
Program AutoNestatickeDatoveSlozky
  • Popis: Deklarace nestatické třídy, nestatických datových složek, zpřehlednění kódu - oblasti
  • Zadání: Deklarujte nestatickou třídu Auto v rámci jmenného prostoru Trida, která bude obsahovat následující datové složky:
    • pocetKol – počet kol auta (konstantní volně přístupný atribut)
    • kapacitaNadrze – kapacita nádrže auta (pouze pro čtení)
    • sPZ – státní poznávací značka auta
    • stavNadrze – aktuální stav objemu paliva v nádrži auta
    • ujetoKm – aktuální stav počtu ujetých kilometrů
    • spotreba – průměrná spotřeba litrů paliva na 100 km

      Pro zpřehlednění kódu využijte značku oblasti (region), abyste oddělili datové složky od zbývajícího kódu
  • Řešení: Bude postupně probráno v následujícím textu (zdrojový kód tohoto příkladu bude využit pro sestavení konečné podoby třídy Auto)


Pojďme si zkusit deklarovat třídu Auto v rámci jmenného prostoru Trida – viz Kód 1. V této třídě využijeme rozdělení kódu do jednotlivých oblastí, abychom kód ve Visual Studio zpřehlednili. K tomu využijeme značku pro specifikace začátku oblasti #region a značku #endregion k označení konce oblasti. Tuto oblast pak můžeme v kódu sbalit (značka – nalevo od zdrojového kódu), nebo následně rozbalit (značka +) – viz kapitola Přehlednost kódu. Pokud máme delší zdrojový kód, použití oblastí může kód velmi zpřehlednit. 

U datových složek neuvádíme klíčové slovo private, protože to je implicitně přednastaveno u každé datové složky, pokud není uveden její modifikátor přístupu. K takovým složkám lze tedy přistoupit uvnitř třídy. Tato třída bude obsahovat pro začátek pouze pár datových složek. pocetKol – počet kol auta je uveden pro ilustraci použití klíčového slova const, tzn., že počet kol nesmí být změněn. Inicializace musí být provedena v rámci deklarace. kapacitaNadrze – kapacita nádrže auta je datová složka pouze pro čtení, tzn. použití klíčového slova readonly. Tuto složku jsme inicializovali v deklaraci. Složka však nemusí být inicializována přímo v deklaraci. Tuto hodnotu lze změnit i v rámci konstruktoru. 

using System;
 
//Deklarace třídy
namespace Trida
{
    //Deklarace třídy 'Auto'
    class Auto
    {
        //Značka začátku oblasti s datovými složkami
        #region Deklarace datových složek třídy
 
        //Deklarace konstantní datové složky
        public const int pocetKol = 4;
        //Deklarace datové složky pouze pro čtení
        readonly double kapacitaNadrze = 60;
        //Deklarace privátních datových složek
        string sPZ;
        double stavNadrze;
        double ujetoKm;
        double spotreba;
        
        //Značka konce oblasti s datovými složkami
        #endregion
 
        //Deklarace hlavní metody
        static void Main(string[] args)
        {
        }
    }
}

Kód 1: Příklad deklarace nestatických datových složek uvnitř třídy Auto včetně využití rozdělení kódu do oblasti


5.2. Statické datové složky

Statické datové složky nejsou součástí jednotlivých instancí, ale pouze třídy jako takové. Datové složky jsou společné pro všechny instance (lze je vnímat jako globální proměnné uvnitř třídy) a jsou uvozeny klíčovým slovem static. Obecná syntaxe nestatické datové složky může vypadat následovně:

modifikátorPřistupu static modifConstRead datovýTyp identifikátor;

modifikátorPřistupu static modifConstRead datovýTyp identifikátor = inicializace;

kde:

  • static - klíčové slovo označující, že jde o statickou datovou složku
  • Podstata u ostatní částí je stejná jako v případě nestatické datové složky – viz kapitola Nestatické datové složky.

Protože jsou statické datové složky společné pro všechny instance, existují nezávisle na tom, kolik instancí vytvoříme. Existují od okamžiku spuštění programu, před vytvořením první instance a existují i po zániku poslední instance. [3]

 

Ilustrativní příklad AutoStatickaDatovaSlozka
Program AutoStatickaDatovaSlozka
  • Popis: Deklarace nestatické třídy, statické datové složky
  • Zadání: V rámci předchozí nestatické třídy Auto v rámci jmenného prostoru Trida, deklarujte statickou celočíselnou datovou složku delkaGrafUkazatele
  • Řešení: Bude postupně probráno v následujícím textu (zdrojový kód tohoto příkladu bude využit pro sestavení konečné podoby třídy Auto)


V případě třídy Auto bychom si mohli graficky zobrazit aktuální stav paliva v nádrži auta. Tento stav zobrazíme v hranatých závorkách, mezi nimiž umístíme znaky "#", které budou zobrazovat aktuální stav paliva uvnitř nádrže. Počet celkových dílků grafického ukazatele stavu paliva tedy pro jednotlivé instance třídy Auto bude konstantní, ale zároveň chceme mít možnost jej modifikovat kvůli různým typům aut - objem nádrže je různý. Proto tuto datovou složku třídy Auto reprezentující počet znaků v grafickém ukazateli budeme deklarovat jako statickou – viz Kód 1.

//Deklarace statické datové složky
static int delkaGrafUkazatele;

Kód 1: Příklad deklarace statické datové složky uvnitř třídy Auto

Dalším typem statické složky je veřejná konstanta deklarovaná ve třídě – hodnota konstanty se nezmění. Datová složka sice nepoužívá klíčové slovo static, ale přesto je svojí podstatou statická.  [6]


6. Metody

Metody reprezentují operace, které lze provádět s instancemi nebo přímo s třídou. Volání metody představuje poslání zprávy instanci (princip OOP) nebo třídě. Metody mohou být statické nebo nestatické. U metod lze využívat různé modifikátory přístupu, stejně jako u datových složek – viz kapitola Tělo třídy. Jedná se o stejné metody práce, které jsme již dříve probírali (metody byly deklarovány v rámci třídy) – viz kniha Metody.


6.1. Statické metody

Volání v případě statické metody představuje zprávu odeslání celé třídě, a ne konkrétní instanci. I to je občas zapotřebí např. při vytvoření nového objektu, kolik bylo již vytvořeno instancí třídy apod.


Ilustrativní příklad TridaStatickaMetoda
Program TridaStatickaMetoda
  • Popis: Deklarace nestatické třídy, deklarace statické metody uvnitř této třídy
  • Zadání: Deklarujte nestatickou třídu Trida, která bude obsahovat hlavní metodu Main ve které budete volat statickou metodu StatickaMetoda. StatickaMetoda bude pouze obsahovat výpis textu "Nyní probíhá statická metoda ve stejné třídě"
  • Řešení: Bude postupně probráno v následujícím textu


Volání statické metody z jiné metody v rámci téže třídy není zapotřebí uvádět třídu. V následujícím kódu vidíme, volání statické metody z hlavní statické metody Main nestatické třídy – viz Kód1. Takto jsme volali statické metody, které jsme doposud vytvářeli.

//Deklarace třídy
class Trida
{
    //Deklarace soukromé statické metody třídy
    static void StatickaMetoda()
    {
        Console.Write("Nyní probíhá statická metoda ve stejné třídě");
    }
 
    static void Main(string[] args)
    {
        //Volání statické metody v rámci stejné třídy
        StatickaMetoda();
        //Čekání na stisk klávesy -> ukončení programu
        Console.ReadKey();
    }
}

Kód 1: Příklad volání statické metody ve stejné nestatické třídě

Na výpisu v konzoli vidíme, že proběhlo volání statické metody v rámci stejné nestatické třídy – viz Výstup programu - Kód 1.

Nyní probíhá statická metoda ve stejné třídě

Výstup programu - Kód 1: Ukázka výsledku volání statické metody ve stejné nestatické třídě


Ilustrativní příklad StatickaMetodaJinaTrida
Program StatickaMetodaJinaTrida
  • Popis: Deklarace jiné nestatické třídy, deklarace statických metod, volání statické metody jiné nestatické třídy
  • Zadání: Deklarujte dvě nestatické třídy Trida a JinaTrida. Trida bude obsahovat hlavní metodu Main, ve které budete volat statickou metodu StatickaMetoda. StatickaMetoda bude pouze obsahovat výpis textu "Nyní probíhá statická metoda ve stejné třídě"
  • Řešení: Bude postupně probráno v následujícím textu


Pokud bychom ale volali metodu jiné třídy, třídu volané metody musíme uvést – viz Kód 2.

namespace StatickaMetodaJinaTrida
{
    //Deklarace nestatické třídy
    class Trida
    {
        static void Main(string[] args)
        {
            //Volání statické metody z jiné třídy
            JinaTrida.StatickaMetoda();
            //Čekání na stisk klávesy -> ukončení programu
            Console.ReadKey();
        }
    }
 
 
    //Deklarace jiné nestatické třídy
    class JinaTrida
    {
        //Deklarace soukromé statické metody jiné třídy
        public static void StatickaMetoda()
        {
            Console.WriteLine("Nyní probíhá statická metoda v jiné třídě");
        }
    }
}

Kód 2: Příklad volání statické metody jiné nestatické třídy v metodě Main implementované uvnitř nestatické třídy

Na výpisu v konzoli vidíme, že proběhlo volání metody z jiné třídy – viz Výstup programu - Kód 2.

Nyní probíhá statická metoda v jiné třídě

Výstup programu - Kód 2: Ukázka výsledku volání statické metody jiné nestatické třídy

6.2. Metoda Main

Neměli bychom také opomenout důležitou statickou metodu Main, která představuje vstupní bod programu. Musí ji obsahovat alespoň jedna třída v programu, jinak kompilátor ohlásí chybu. Může ji obsahovat ale i více tříd. Pak musíme specifikovat, pomocí parametru 

/main:jménoTřídy

 kterou metodu Main má použít jako vstupní bod.

U metody Main platí následující pravidla:

  • Metoda Main je vstupní bod programu C#, odkud začíná provádění programu

  • Metoda Main musí být statická, protože se jedná o metodu na úrovni třídy. Nestatická metoda Main způsobí chybu při kompilaci

  • Metodu Main nelze překrýt, protože se jedná o statickou metodu. Statická metoda také nemůže být virtual nebo abstract

  • Přetížení metody Main je povoleno. V takovém případě pouze jedna metoda Main() se však považuje za jeden vstupní bod pro spuštění provádění programu [13]

Metoda Main musí mít jednu z následujících podob:

public static void Main();

public static void Main(string[] args);

public static int Main();

public static int Main(string[] args);

kde:

  • string[] args - představuje pole řetězců, které obsahuje parametry z příkazového řádku programu. Pokud tato metoda vrací int, musí obsahovat příkaz return. Vrácená hodnota se interpretuje jako kód ukončení programu; 0 podle konvence znamená, že je vše v pořádku, nenulová čísla představují kód chyby. [3]

6.3. Nestatické metody

Nestatickou metodu (není deklarována klíčovým slovem static) lze volat pouze na konkrétní instanci třídy. Tato metoda může pracovat s datovými složkami této instance. Volání metody představuje zprávu poslanou instancí. Instanci třídy vytváříme pomocí konstruktoru – viz kapitola Konstruktory. Pokud voláme v těle nestatické metody další nestatickou metodu pro tutéž instanci, jméno instance nemusíme uvádět.

Nestatické metody třídy lze volat v nestatických metodách pomocí klíčového slova this. Jedná se o odkaz na konkrétní instanci třídy. Pomocí this lze také přistoupit k nestatickým datovým složkám.


Ilustrativní příklad TridaStatickaNestatickaSlozka
Program TridaStatickaNestatickaSlozka
  • Popis: Deklarace nestatické třídy, deklarace statické a nestatické složky uvnitř této třídy
  • Zadání: Deklarujte nestatickou třídu Trida, která bude obsahovat hlavní metodu Main, ve které vypíšete hodnoty deklarované statické celočíselné složky a a nestatické datové složky b, které jsou deklarovány uvnitř třídy. Deklarujte soukromou (privátní) nestatickou metodu Soucet uvnitř této třídy. Tato metoda navrací součet obou datových složek. Zkuste v metodě Main vypsat hodnoty obou datových složek, aniž by byly inicializovány, nebo by jim byly přiřazeny nějaké hodnoty
  • Řešení: Bude postupně probráno v následujícím textu


V následujícím příkladu si zkusíme ve statické metodě Main použít statickou a nestatickou datovou složku – viz Kód 1. Jak vidíme v prvním příkazu metody Main, šlo přistoupit k soukromé statické datové složce. Ve druhém případu přístupu k soukromé nestatické složce bychom úspěšní nebyli. Kompilátor by zahlásil chybu. V kódu jsme také deklarovali nestatickou soukromou metodu Soucet, která navrací součet hodnoty ve statické a nestatické složce třídy. Jak vidíme, tuto metodu nelze volat v rámci statické metody Main, i když je metoda Main deklarována rámci téže třídy.

//Deklarace třídy
class Trida
{
    //Deklarace soukromé statické datové složky
    static int a;
    //Deklarace soukromé nestatické datové složky
    int b;
 
    //Deklarace soukromé nestatické metody třídy
    int Soucet()
    {
        return (a + this.b);
    }
 
    static void Main(string[] args)
    {
        //Použití soukromé statické datové složky
        Console.WriteLine(a);
        //Nelze použít soukromou nestatické datovou složku -> K.O.
        Console.WriteLine(b);
        //Nelze volat nestatickou metodu v rámci stejné třídy -> K.O.
        Console.WriteLine(Soucet());
        //Čekání na stisk klávesy -> ukončení programu
        Console.ReadKey();
    }
}

Kód 1: Příklad volání nestatické metody ve statické metodě, použití soukromé statické a nestatické složky


Vraťme se k příkladu našeho auta. 


Ilustrativní příklad AutoUjedTrasu

Program AutoUjedTrasu

  • Popis: Deklarace veřejné metody třídy Auto
  • Zadání: Deklarujte veřejnou metodu bez návratu s názvem UjedTrasu ve třídě Auto, která simuluje jízdu auta. Využijte deklarovaných datových složek v předchozím programu AutoNestatickeDatoveSlozky. Tato metoda přijímá jako vstupní reálný formální parametr pocetKm, který vyjadřuje počet km, které má auto ujet. V rámci této metody je volána další metoda SpotrebujPalivo, která zajistí spotřebu paliva pro jízdu auta (datová složka stavNadrze). Je zároveň nutné zvýšit počet ujetých kilometrů auta (datová složka ujetoKm). Deklarujte metodu StavNadrzeGraficky pro zobrazení grafického prvku, který ukazuje aktuální stav paliva v nádrži (návrat metody ve formě textového řetězce). Grafický ukazatel stavu paliva budou reprezentovat znaky "#" uzavřené v hranatých závorkách
  • Řešení: Bude postupně probráno v následujícím textu (zdrojový kód tohoto příkladu bude využit pro sestavení konečné podoby třídy Auto)


Účelem našeho auta je jezdit různé trasy. K tomu využijeme veřejnou metodu bez návratu s názvem UjedTrasu - viz Kód 2. Vzdálenost, kterou má auto ujet, je specifikována pomocí formálního parametru pocetKm. Tento vstupní parametr je předán hodnotou. V metodě zavoláme další metodu třídy spotrebujPalivo, která zajistí, že bude spotřebováno palivo v nádrži v závislosti na počtu ujetých kilometrů. Pro volání metody jsme využili klíčového slova this a tečkové notace (anglicky „Dot Notation“) , ale vzhledem k tomu, že metodu deklarujeme ve stejné třídě, to není nutné. Mohli jsme pouze uvést název metody. Ujeté kilometry se nám také musí odrazit v celkovém počtu ujetých kilometrů auta. Musíme tedy zvýšit hodnotu soukromé datové složky ujetoKm o hodnotu počtu ujetých kilometrů na trase pomocí operátoru +=.

//Deklarace veřejné metody pro ujetí určité trasy
public void UjedTrasu(double pocetKm)
{
    //Volání metody pro spotřebu paliva
    this.SpotrebujPalivo(pocetKm);
    //Zvýšení celkového počtu ujetých kilometrů
    this.ujetoKm += pocetKm;
}

Kód 2: Příklad deklarace veřejné metody UjedTrasu ve třídě Auto – spotřeba paliva na ujetí trasy

Naše auto by mělo spotřebovat pohonnou látku, pokud uskuteční jízdu. Za tímto účelem byla deklarována soukromá metoda bez návratu s názvem SpotrebujPalivo, která přijímá počet ujetých kilometrů na jízdu auta jako formální parametr pocetKm - viz Kód 3. Na základě výpočtu spotřebovaného paliva pomocí spotřeby a ujetého počtu kilometrů spočteme spotřebované palivo na jízdu (vypočtenou hodnotu uložíme do lokální proměnné spotrebovanePalivo). Vypočtenou hodnotu spotřebovaného paliva musíme zároveň odebrat z nádrže pomocí operátoru -= (z datové složky stavNadrze).

//Deklarace soukromé metody pro výpočet spotřeby a snížení množství paliva
private void SpotrebujPalivo(double pocetKm)
{
    //Výpočet spotřebovaného paliva 
    double spotrebovanePalivo = pocetKm / 100 * this.spotreba;
    //Odebrání spotřebovaného paliva z nádrže
    this.stavNadrze -= spotrebovanePalivo;
}

Kód 3: Příklad deklarace soukromé metody SpotrebujPalivo ve třídě Auto – spotřeba paliva

Další veřejnou metodou StavNadrzeGraficky kterou budeme využívat, je zobrazení grafického ukazatele, který nám ukáže, jaký je aktuální stav paliva v nádrži - viz Kód 4. Grafický ukazatel ve formě textového řetězce bude zobrazen v hranatých závorkách, mezi nimiž jsou umístěny znaky "#", které zobrazují aktuální stav paliva v nádrži auta.

Počet dílků tedy pro jednotlivé instance třídy Auto bude konstantní, proto je tato datová složka deklarována jako statická (datová složka delkaGrafUkazatele). Pro přístup k této datové složce jsme využili třídu Auto a pomocí tečkové notace přistoupili k této statické složce (vzhledem k tomu, že jsme v rámci téže třídy, lze vynechat Auto.). V další příkazu jsme ve výrazu využili funkci Round třídy Math, která nám zaokrouhlí na celé číslo vypočtenou procentuální hodnotu objemu paliva v nádrži vzhledem k celkové kapacitě nádrže. Pro zapsání počtu znaků "#" (reprezentujících objem paliva v nádrži) jsme využili cyklus s krokem, protože víme, kolik znaků má být zapsáno uvnitř hranatých závorek ukazatele. Pro připojení znaků do textového řetězce zprava jsme využili operátor +=. Po vypsání znaků "#" musíme doplnit mezery do konce hranaté závorky (mezery budou zobrazovat prázdnou nádrž). K tomu jsme využili příkaz PadRight datového typu string, který navrací řetězec zadané délky, ve kterém je konec řetězce vyplněn mezerami. K výslednému textovému řetězci připojíme konečnou hranatou závorku a pomocí příkazu return předáme výsledkem do metody, ze které byla tato metoda volána.

//Deklarace veřejné metody pro grafiku zobrazující aktuální stav paliva v nádrži
public string StavNadrzeGraficky()
{
    //Deklarace grafického výstupu - textový řetězec - počátek hranaté závorky
    string grafickyUkazatel = "[";
    /*Výpočet procentuálního objemu paliva v nádrži a výpočet počtu dílků 
     * v grafickém ukazateli, tj. počet znaků # uvnitř hranaté závorky*/
    double pocetDilku = Math.Round((this.stavNadrze / this.kapacitaNadrze) *
        Auto.delkaGrafUkazatele);
    //Cyklus na připojení znaků do grafického výstupu
    for (int i = 0; i < pocetDilku; i++)
        grafickyUkazatel += "#";
    //Doplnění mezer do celkové délky grafického ukazatele
    grafickyUkazatel = grafickyUkazatel.PadRight(Auto.delkaGrafUkazatele + 1);
    //Návrat grafického textového ukazatele stavu paliva v nádrži 
    return (grafickyUkazatel += "]");
}

Kód 4: Deklarace veřejné metody StavNadrzeGraficky ve třídě Auto – grafický ukazatel spotřeby paliva

7. Konstruktory

Konstruktor je metoda třídy, pomocí níž vytváříme instance za běhu programu. V konstruktoru jsou inicializovány všechny datové složky, kromě těch, které byly inicializovány přímo v deklaraci datových složek třídy (za běhu programu se vytýčí část paměti operačního systému a zaberou je datovými složkami třídy a poté je zavolán konstruktor). Syntaxe deklarace konstruktoru vypadá následovně:

hlavičkaKonstruktoru inicializátor těloKonstruktoru 

kde:

  • hlavičkaKonstruktoru - se podobá hlavičce metody a obsahuje modifikátory přístupu kromě modifikátoru sealed nebo abstract! Hlavička nesmí obsahovat datový typ vrácené hodnoty a ani void. Název (identifikátor) konstruktoru je stejný jako název třídy, které náleží, budeme ho tedy vždy značit velkým počátečním písmenem. Pokud je deklarováno více konstruktorů, musí se lišit počtem, typem nebo pořadím typů parametrů – přetížení

  • inicializátor - je nepovinný. Inicializátor může mít jednu z následujících podob:
:base(skutečnéParametry)

:this(skutečnéParametry)

U první možnosti se jedná o vyvolání konstruktoru předka (více se dozvíme později). Druhý typ inicializátoru zavolá jiný konstruktor téže třídy, před provedením těla tohoto konstruktoru. [3]

Některá třída může být docela velká, proto ji lze rozdělit do několika menších celků, které jsou uloženy v různých souborech. Toto dělení se provádí pomocí klíčového slova partial. Díky tomu lze oddělit i jednotlivé datové složky, metody a konstruktory jedné třídy.


7.1. Implicitní konstruktor

Pokud ve třídě nedefinujeme vlastní konstruktor, vytvoří si ho kompilátor sám a my ho můžeme používat. Tento výchozí konstruktor nepřijímá žádné parametry. Takový konstruktor má prázdné tělo, a pokud je veřejně přístupný (public), můžeme vytvářet instance z jiné třídy.

Konstruktor voláme při vytváření nové instance pomocí operátoru new. Syntaxe volání konstruktoru vypadá následovně:

new identifikátorTřídy()

Hodnotou takového výrazu konstruktoru je odkaz na vytvořenou instanci třídy. Konstruktory se nedědí.

Vraťme se k příkladu třídy Auto. 


Ilustrativní příklad AutoImplicitniKonstruktor
Program AutoImplicitniKonstruktor
  • Popis: Vytvoření instance třídy pomocí implicitního konstruktoru
  • Zadání: Vytvořte novou instanci třídy autoOctavia předchozí nestatické třídy Auto 
  • Řešení: Bude postupně probráno v následujícím textu

Pomocí následujícího kódu vytvoříme instanci této třídy pomocí zavolání implicitního (výchozího) konstruktoru – viz Kód 1. Tento typ konstruktoru voláme, pokud si nedeklarujeme vlastní konstruktor ve třídě. Pokud datové složky nebyly přímo inicializovány při deklaraci, jsou jim automaticky nastaveny výchozí předdefinované hodnoty – viz kapitola Nestatické datové složky - Tabulka 1. Instanci pojmenujeme autoOctavia.

//Vytvoření instance třídy Auto pomocí volání implicitního konstruktoru
Auto autoOctavia = new Auto();

Kód 1: Příklad vytvoření instance třídy Auto pomocí implicitního konstruktoru

7.2. Vlastní konstruktor

V minulém případě implicitního konstruktoru jste asi vnímali, že by bylo vhodné si vytvořit vlastní konstruktor, kterému mu předáme skutečné parametry a těmi naplníme jednotlivé datové složky vytvářené instance. K jednotlivým datovým složkám třídy a zároveň k jejím metodám  přistupujeme pomocí tečkové notace (anglicky „Dot Notation“). Pomocí klíčového slova this přistupujeme do obsahu třídy. 

Syntaxe volání vlastního konstruktoru vypadá následovně:

new identifikátorTřídy(skutečnéParametry)

kde:

  • identifikátorTřídy - název třídy, podle které bude generována instance
  • skutečnéParametry - uvádění skutečných parametrů není povinné (konstruktor nemusí přijímat žádné parametry, záleží na nás, jak budeme specifikovat vlastní konstruktor). Hodnotou takového výrazu konstruktoru je odkaz na vytvořenou instanci třídy. Implicitní ani vlastní konstruktory se nedědí.


Ilustrativní příklad AutoVlastniKonstruktor
Program AutoVlastniKonstruktor
  • Popis: Vytvoření instance třídy pomocí vlastního konstruktoru, inicializace datových složek třídy
  • Zadání: Vytvořte novou instanci třídy autoOctavia předchozí nestatické třídy Auto pomocí vlastního konstruktoru. Konstruktor bude přijímat jako formální parametry kapacitaNadrze, stavNadrze, spotreba (datové typy těchto parametrů jsou shodné s datovými typy datových složek třídy Auto). Nastavte délku grafického ukazatele paliva (nádrž je plná) na 20 znaků. Počáteční stav najetých km (ujetoKm) je 0. V hlavní metodě vytvořte instanci třídy Auto s názvem autoOctavia se skutečnými parametry 55, 50, 0 (kapacitaNadrze, stavNadrze, spotreba). Vypište v Main kapacitu nádrže, stav ujetých km, objem nádrže a zobrazte objem nádrže pomocí grafického prvku. Ujeďte s autem 100 km a proveďte znovu všechny výpisy
  • Řešení: Auto_Main 
    (spojení programů AutoNestatickeDatoveSlozky + AutoStatickaDatovaSlozka + AutoUjedTrasu + AutoVlastniKonstruktor)


V konstruktoru nazvaným stejným jménem jako třída, tedy Auto, jsme využili formální parametry pro inicializaci datových složek. První parametr kapacitaNadrze je určen k definování skutečného objemu nádrže auta. Výchozí kapacitu nádrže jsme již dříve inicializovali přímo v deklaraci této datové složky (přiřadili jsme jí hodnotu 60 litrů). Každé auto však bude mít jinou kapacitu nádrže, proto tato datová složka má modifikátor přístupu typu readonly, takže ji lze přiřadit jinou hodnotu v konstruktoru, což právě provedeme pomocí hodnoty ve formálním parametru kapacitaNadrze. Dalším formálním parametrem stavNadrze jsme nastavili objem paliva v nádrži auta. Jako poslední jsme použili parametr spotreba a tím jsme nastavili deklarovanou spotřebu litrů paliva na 100 km jízdy autem. 

//Deklarace vlastního konstruktoru třídy
public Auto(double kapacitaNadrze, double stavNadrze, double spotreba)
{
    //Inicializace soukromých datových složek
    this.stavNadrze = stavNadrze;
    this.ujetoKm = 0;
    this.spotreba = spotreba;
    //Inicializace statické datové složky
    delkaGrafUkazatele = 20;
    //Inicilazace datové složky (readonly) pomocí parametru
    this.kapacitaNadrze = kapacitaNadrze;
}

Kód 1: Příklad deklarace vlastního konstruktoru třídy Auto

Pokud v kódu používáme stejný název parametru, jako je název datové složky, nelze vynechat klíčové slovo this – viz Kód 2. Kompilátor oznámí: Přiřazení proběhlo u stejné proměnné. Kompilátor totiž neví, že identifikátor vlevo od přiřazení byl zamýšlen jako datová složka a vpravo jako hodnota parametru. Formální parametr se stejným názvem jako datová složka totiž skryje datovou složku uváděnou v příkazech metody (je upřednostněn formální parametr – lokálnost). 

/*Inicilazace datové složky (readonly) pomocí parametru
 * s vynecháním this. Kompilátor neví, že se jedná o přiřazení
 * hodnoty parametru do datové složky -> K.O. */
kapacitaNadrze = kapacitaNadrze;

Kód 2: Příklad důsledku nepoužití klíčového slova this při stejném názvu datové složky a formálního parametru

V následujícím kódu je volán vlastní konstruktor Auto třídy Auto, kterému jsou předány skutečné parametry 55, 50, 5, jejichž hodnota je přiřazena do příslušných datových složek (kapacitaNadrze, stavNadrze, spotreba). Pomocí klíčového slova new je vytvořena instance třídy, která je přiřazena objektu autoOctavia třídy Auto. Po proběhnutí těla konstruktoru tedy náš objekt autoOctavia nebude mít kapacitu nádrže 60 litrů, ale jen 55 litrů. Dále jsme nastavili objem nádrže na 50 litrů a definovali spotřebu 5 litrů paliva na 100 km – viz Kód 3. 

//Deklarace hlavní metody
static void Main(string[] args)
{
    /*Vytvoření instance třídy Auto pomocí volání vlastního konstruktoru
     * včetně předání skutečného parametru*/
    Auto autoOctavia = new Auto(55, 50, 5);
    Console.WriteLine("Kapacita nádrže: {0}", autoOctavia.kapacitaNadrze);
    Console.WriteLine("Ujeto km: {0}", autoOctavia.ujetoKm);
    Console.WriteLine("Stav nádrže: {0}", autoOctavia.stavNadrze);
    Console.WriteLine("Stav nádrže: {0}", autoOctavia.StavNadrzeGraficky());
    autoOctavia.UjedTrasu(100);
    Console.WriteLine("Auto Octavia:");
    Console.WriteLine("Ujeto km: {0}", autoOctavia.ujetoKm);
    Console.WriteLine("Stav nádrže: {0}", autoOctavia.stavNadrze);
    Console.WriteLine("Stav nádrže: {0}", autoOctavia.StavNadrzeGraficky());
    //Čekání na stisk klávesy -> ukončení programu
    Console.ReadKey();
}

Kód 3: Deklarace hlavní metody třídy Auto - vytvoření instance autoOctavia a výpis hodnot datových složek

V následujícím výpisu v konzole vidíme stav autoOctavia před jízdou a po ujetí 100 km - viz Výstup programu - Kód Auto_Main. 

Kapacita nádrže: 55
Ujeto km: 0
Stav nádrže: 50
Stav nádrže: [##################  ]
Auto Octavia:
Ujeto km: 100
Stav nádrže: 45
Stav nádrže: [################    ]

Výstup programu - Kód Auto_Main

7.3. Statický konstruktor

Deklarace třídy může obsahovat také jeden statický konstruktor (použití modifikátoru static). Takový konstruktor slouží k inicializaci statických složek třídy (včetně složek s modifikátorem readonly), které nejsou inicializovány přímo v deklaraci. Takové konstruktory nesmí obsahovat žádné parametry. Ani statický konstruktor se nedědí. [3]


8. Dekonstrukce instance

Konstruktor jsme použili pro vytvoření instance třídy a inicializaci datových složek, které instance obsahuje. Dekonstrukce nám umožní prozkoumat instanci a extrahovat hodnoty z jejích datových složek. Obecná syntaxe pro dekonstrukci je následující:

modifikátorPřístupu void Deconstruct (výstupníParametry) 
{
	těloDekonstrukce
}

kde:

  • modifikátorPřístupu - je stejný jako metod a datových složek

  • void - klíčové slovo říkající, že metoda nemá žádný výstup

  • Deconstruct - povinný název metody pro dekonstrukci instance

  • výstupníParametry  - musí existovat minimálně jeden výstupní parametr. výstupníParametry musí být uvozeny klíčovým slovem out, tzn., že hodnoty jim budou přiřazeny teprve v metodě – viz kapitola Výstupní parametry. Všem výstupním parametrům musí být přiřazena hodnota

  • těloDekonstrukce - je uzavřeno do složených závorek

Pro ilustraci uveďme jednoduchý příklad metody dekonstrukce instance bodu na ploše.


Ilustrativní příklad DekonstrukceInstance
Program DekonstrukceInstance
  • Popis: Dekonstrukce objektu třídy
  • Zadání: Vytvořte instanci bodu na ploše bodNaPlose třídy Bod pomocí vlastního konstruktoru. Instance je definována pomocí dvou reálných souřadnic x a y (soukromé datové složky). V hlavní metodě Main konstruktoru předejte x = 5 a y = 7. Dekonstruujte instanci a vypište v Main hodnotu jejích datových složek 
  • Řešení: Bude postupně probráno v následujícím textu


Třídu jsme nazvali Bod. Každá instance (každý bod) je definována pomocí dvou souřadnic: x,y. Tyto reálné hodnoty souřadnic x-ové a y-ové souřadnice bodu uložíme do soukromých datových složek – viz Kód 1. 

//Deklarace třídy pro generování bodu na ploše
class Bod
{
    //Deklarace soukromých datových složek - souřadnice bodu
    double x, y;
}

Kód 1: Deklarace třídy Bod a deklarace soukromých datových složek třídy

Pro třídu bod jsme deklarovali konstruktor, který přijímá jako formální parametry x-ové a y-ové souřadnice bodu. Pomocí těchto hodnot provedeme inicializaci datových složek instance – viz Kód 2.

//Deklarace konstruktoru třídy
public Bod(double x, double y) 
{
    //Incializace datových složek pomocí hodnoty parametrů
    this.x = x;
    this.y = y;
}

Kód 2: Deklarace vlastního konstruktoru třídy Bod

V následujícím kódu je zobrazena metoda dekonstrukce instance třídy Bod. Jedná se o extrahování hodnot uložených v jednotlivých datových složkách instance. Tyto hodnoty jsou v těle metody přiřazeny do výstupních parametrů metody – viz Kód 3.

//Metoda dekonstrukce instance třídy - extrahování datových složek
public void Deconstruct(out double x, out double y)
{
    //Přiřazení hodnoty datové složky do výstupního parametru
    x = this.x;
    y = this.y;
}

Kód 3: Deklarace dekonstruktoru třídy Bod

Zkusme si nyní ve statické metodě Main pomocí konstruktoru vygenerovat bod na ploše o reálných souřadnicích. Nejprve v metodě Main deklarujeme lokální proměnné x a y stejného datového typu jako datové složky třídy. Instanci třídy Bod pojmenujeme bodNaPlose. Tuto instanci vytvoříme pomocí deklarovaného konstruktoru. V dalším kroku použijeme metodu dekonstrukce instance, pomocí níž získáme hodnoty souřadnic bodu, které uložíme do lokálních proměnných x a y. Tyto hodnoty následně vypíšeme – viz Kód 4.

static void Main(string[] args)
{
    //Deklarace reálných proměnných
    double x, y;
    //Zavolání konstruktoru a předání parametrů
    Bod bodNaPlose = new Bod(5, 7);
    //Metoda dekonstrukce instance
    bodNaPlose.Deconstruct(out x, out y);
    Console.WriteLine("Bod na ploše - dekonstrukce:");
    //Výpis hodnot získaných z datových složek instance
    Console.WriteLine("Hodnota x: {0}", x);
    Console.WriteLine("Hodnota y: {0}", y);
    //Čekání na stisk klávesy -> ukončení programu
    Console.ReadKey();
}

Kód 4: Hlavní metoda Main - generování instance bodNaPlose třídy Bod a zavolání dekonstrukce objektu

Na výpisu v konzoli vidíme, že byly vypsány hodnoty datových složek instance bodNaPlose zkopírované do lokálních proměnných – viz Výstup programu - Kód 4. 

Bod na ploše - dekonstrukce:
Hodnota x: 5
Hodnota y: 7

Výstup programu - Kód 4: Výpis hodnot lokálních proměnných obsahující hodnoty datových složek


K dekonstrukci instance lze také využít již nám známý postup návratu více výstupů – viz kapitola Návrat více výstupů. V kódu vidíme, že vpravo od operátoru přiřazení je umístěna instance dané třídy. Vlevo jsou umístěny lokální proměnné, do nichž bude uložena hodnota. C# totiž sám na pozadí spustil dekonstruktor (tato metoda musí být deklarována, jinak metoda s více výstupy nebude fungovat) a naplnil hodnoty do proměnných. Proměnné jsme na začátku před použitím dekonstrukce instance ještě vynulovali, abychom si byli jisti, že metoda návratu více výstupů funguje – viz Kód 5.

//Volání metody pro návrat více výstupů
(x, y) = bodNaPlose;
//Výpis hodnot získaných z datových složek instance
Console.WriteLine("Bod na ploše - více výstupů:");
Console.WriteLine("Hodnota x: {0}", x);
Console.WriteLine("Hodnota y: {0}", y);

Kód 5: Příklad volání metody pro návrat více výstupů


9. Destruktor

Každá třída může obsahovat pouze jeden destruktor (anglicky „Destructor“). Tato metoda má za úkol připravit instanci k zániku – tedy uvolnit systémové prostředky, které instance v průběhu své existence získala např. uzavřít databázová spojení, zavřít otevřený soubor apod.

Deklarace destruktoru má tvar:

~jménoTřídy( ) těloDestruktoru

kde: 

  • vlnovka (neboli tilda – na české klávesnici Alt+126) se umísťuje před jméno třídy. Destruktor nesmí mít parametry a jeho deklarace nesmí obsahovat žádný modifikátor přístupu a ani typ návratové hodnoty. Destruktor nelze volat ve zdrojovém kódu. Prostředí .NET Framework si ho zavolá těsně před tím, než automatická správa paměti (Garbage Collector) odstraní instanci z paměti. Destruktory se nedědí. [3]


10. Anonymní třída

Anonymní třída je třída, která nemá jméno. Sice to může znít zvláštně, ale tento typ třídy je využíván u dotazových výrazů. Anonymní třída se vytváří pomocí klíčového slova new a do složených závorek se umístí definice datových složek a jejich hodnot. U anonymních tříd platí následující pravidla: 

  • Anonymní třídy musí obsahovat pouze veřejné datové složky 
  • Datové složky musí být inicializované 
  • Datové složky nesmí být statické a nelze specifikovat metody [6]


Ilustrativní příklad AnonymniTrida
Program AnonymniTrida
  • Popis: Deklarace anonymní třídy, vytvoření instance, výpis datových složek
  • Zadání: Deklarujte anonymní třídu se dvěma datovými složkami - Jmeno (textový řetězec) a Vek (celé číslo). Do datových složek anonymní instance s názvem anonymniInstance uložte hodnoty "Pavel", 38
  • Řešení: AnonymniTrida_Main

Následující kód vytváří anonymní instanci se dvěma datovými složkami - viz Kód 1. Vzhledem k tomu, že jsme nedefinovali žádné datové typy, kompilátor si je musí odvodit sám z jejich inicializace. Při definici anonymní třídy vygeneruje kompilátor pro tuto třídu její vlastní název (ten se však nedozvíme). Asi si říkáte, jak tedy máme deklarovat instanci této třídy, když neznáme její jméno? Odpověď zní, využijeme deklaraci implicitně typované proměnné, tzn., že použijeme klíčové slovo var – viz kapitola Proměnná – přiřazovací příkaz, výraz. Deklarace takové instance by tedy vypadala následovně. Klíčové slovo var způsobí, že kompilátor si vytvoří proměnnou stejného datového typu, jako je výraz použitý při její deklaraci (v tomto případě je typem výrazu jakékoliv jméno, které použil kompilátor pro vygenerování naší anonymní třídy).

//Deklarace instance anonymní třídy včetně inicializace datových složek anonymní instance
var anonymniInstance = new { Jmeno = "Pavel", Vek = 38 };

Kód 1: Vytvoření instance anonymní třídy

K datovým složkám instance lze přistoupit pomocí tečkové notace – viz Kód 2.

//Výpis hodnoty první datové složky instance anonymní třídy
Console.WriteLine("Jméno: {0}", anonymniInstance.Jmeno);
//Výpis hodnoty druhé datové složky instance anonymní třídy
Console.WriteLine("Věk: {0}", anonymniInstance.Vek);

Kód 2: Výpis hodnot v datových složkách instance anonymní třídy

Na výpisu v konzoli můžeme vidět vypsané hodnoty obou datových složek instance anonymní třídy - viz Výstup programu - Kód AnonymniTrida_Main.

Anonymní instance:
Jméno: Pavel
Věk: 38

Výstup programu - Kód AnonymniTrida_Main: výpis hodnot datových složek instance anonymní třídy


Další anonymní instance této třídy lze vytvářet stejným způsobem – viz Kód 3. Kompilátor používá názvy, typy, počet a pořadí datových složek ke stanovení, zda dvě instance anonymní třídy mají stejný typ.

//Deklarace další instance anonymní třídy včetně inicializace datových složek
var jinaAnonymniInstance = new { Jmeno = "Petr", Vek = 39 };

Kód 3: Příklad vytvoření další instance anonymní třídy

Pořadí plnění datových složek jsme záměrně prohodili za účelem testování – viz Kód 4. To je však jedno v tomto případě jedno, protože jednotlivé datové složky jsou pojmenovány a mají shodný datový typ.

//Prohození datových složek instance anonymní třídy
var jinaAnonymniInstance = new { Vek = 39, Jmeno = "Petr" };

Kód 4: Příklad vytvoření další instance anonymní třídy – prohození datových složek

Anonymní instanci lze přiřadit jiné anonymní instanci – viz Kód 5. Pokud se ale myslíte, že se vytvoří kopie takové instance, není to pravda! Vytvoří se pouze odkaz na jednu stejnou instanci. Vše co provádíte anonymniInstance se provádí i s jinaAnonymniInstance. 

//Přiřazení instance jiné instanci
jinaAnonymniInstance = anonymniInstance;

Kód 5: Příklad přiřazení instance třídy jiné instanci anonymní třídy

11. Stručné shrnutí

Stručné shrnutí kapitol
Pro ...... uveďte následující
Deklarace soukromé datové složky třídyV těle třídy uveďte modifikátor přístupu datové složky, její datový typ a jméno datové složky, např.: 
class Bod 
{
    private int x;
}
Přístup k soukromé datové složce třídyPro přístup k seznamu atributů třídy, např. datových složek třídy, použijte klíčové slovo this následovaný tečkou a uveďte název datové složky, např.:
this.x = x;
Deklarace soukromé statické datové složky třídyV těle třídy uveďte modifikátor přístupu datové složky, za ním uveďte klíčové slovo static, datový typ datové složky a jméno datové složky, např.: 
class Bod 
{
    ...
    private static int pocetBodu = 0;
}
Přístup k soukromé statické datové složce třídyPro přístup k seznamu atributů třídy, např. statické datové složky třídy, použijte název třídy následovaný tečkou a uveďte název statické datové složky, např.:
Bod.pocetBodu++;
Deklarace konstantní datové složkyV těle třídy uveďte modifikátor přístupu datové složky, za ním uveďte klíčové slovo const, dále uveďte datový typ složky a jméno této datové složky, např.: 
class Bod 
{
    ... 
    public const double PI = ...;
} 
Deklarace konstruktoruUveďte metodu, jejíž název je shodný s názvem třídy. Tato metoda nemá žádný návratový typ (ani void), např.:
class Bod 
{
    ...
 
    public Bod(int x, int y)
    {
        ...
    }
}
Zavolání konstruktoruUveďte klíčové slovo new a název konstruktoru s příslušnými parametry, např.:
Bod novyBod = new Bod(0, 0);
Deklarace statické metodyUveďte před deklarací metody klíčové slovo static, např.: 
class Bod 
{
    public static int PocetBodu()
    {
        ...
    }
}
Zavolání statické metodyUveďte název třídy následovaný tečkou a za ní uveďte název statické metody, např.:
int pocetObjektu = Bod.PocetBodu();