Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

10. diel - Vlastnosti

V predchádzajúcom cvičení, Riešené úlohy k 9. lekcii OOP v C # .NET, sme si precvičili získané skúsenosti z predchádzajúcich lekcií.

V minulej lekcii, Riešené úlohy k 9. lekcii OOP v C # .NET , sme si vysvetlili statiku. V dnešnom C # .NET tutoriálu sa pozrieme na ďalšie prvky tried, ktoré ešte nepoznáme. Začnime prisľúbeným vlastnosťami.

Vlastnosti

Veľmi často sa nám stáva, že chceme mať kontrolu nad zmenami nejakého atribútu objektu zvonku. Budeme chcieť atribút nastaviť ako read-only alebo reagovať na jeho zmeny. Založme si nový projekt (názov Vlastnosti ) a vytvorme nasledujúce triedu Student , ktorá bude reprezentovať študenta v nejakom informačnom systéme.

class Student
{
    public string jmeno;
    public bool muz;
    public int vek;
    public bool plnolety;

    public Student(string jmeno, bool pohlavi, int vek)
    {
        this.jmeno = jmeno;
        this.muz = pohlavi;
        this.vek = vek;
        plnolety = true;
        if (vek < 18)
            plnolety = false;
    }

    public override string ToString()
    {
        string jsemPlnolety = "som";
        if (!plnolety)
            jsemPlnolety = "nie som";
        string pohlavi = "muž";
        if (!muz)
            pohlavi = "žena";
        return String.Format("Som {0}, {1}. Je mi {2} rokov a {3} plnoletý.", jmeno, pohlavi, vek, jsemPlnolety);
    }

}

Trieda je veľmi jednoduchá, študent sa nejako volá, je nejakého pohlavia a má určitý vek. Podľa tohto veku sa nastavuje atribút plnolety pre pohodlnejšie vyhodnocovanie plnoletosti na rôznych miestach systému. Na uloženie pohlavia používame hodnotu bool , či je študent muž. Konštruktor podľa veku určí, či je študent plnoletý. Metóda ToString() je navrhnutá pre potreby tutoriálu tak, aby nám vypísala všetky informácie. V reáli by vrátila pravdepodobne len meno študenta. Pomocou konstruktoru si nejakého študenta vytvorme:

            Student s = new Student("Pavel Hora", true, 20);
            Console.WriteLine(s);
    class Student
    {
        public string jmeno;
        public bool muz;
        public int vek;
        public bool plnolety;

        public Student(string jmeno, bool pohlavi, int vek)
        {
            this.jmeno = jmeno;
            this.muz = pohlavi;
            this.vek = vek;
            plnolety = true;
            if (vek < 18)
                plnolety = false;
        }

        public override string ToString()
        {
            string jsemPlnolety = "som";
            if (!plnolety)
                jsemPlnolety = "nie som";
            string pohlavi = "muž";
            if (!muz)
                pohlavi = "žena";
            return String.Format("Som {0}, {1}. Je mi {2} rokov a {3} plnoletý.", jmeno, pohlavi, vek, jsemPlnolety);
        }

    }

výstup:

Konzolová aplikácia
Som Pavel Hora, muž. Je mi 20 rokov a som plnoletý.

Všetko vyzerá pekne, ale atribúty sú prístupné ako na čítanie, tak na zápis. Objekt teda môžeme rozbiť napríklad takto (hovoríme o nekonzistentnom vnútorným stave):

            Student s = new Student("Pavel Hora", true, 20);
            s.vek = 15;
            s.muz = false;
            Console.WriteLine(s);
            Console.ReadKey();
    class Student
    {
        public string jmeno;
        public bool muz;
        public int vek;
        public bool plnolety;

        public Student(string jmeno, bool pohlavi, int vek)
        {
            this.jmeno = jmeno;
            this.muz = pohlavi;
            this.vek = vek;
            plnolety = true;
            if (vek < 18)
                plnolety = false;
        }

        public override string ToString()
        {
            string jsemPlnolety = "som";
            if (!plnolety)
                jsemPlnolety = "nie som";
            string pohlavi = "muž";
            if (!muz)
                pohlavi = "žena";
            return String.Format("Som {0}, {1}. Je mi {2} rokov a {3} plnoletý.", jmeno, pohlavi, vek, jsemPlnolety);
        }

    }

výstup:

Konzolová aplikácia
Som Pavel Hora, žena. Je mi 15 rokov a som plnoletý.

Určite musíme ošetriť, aby sa plnoletosť obnovila pri zmene veku. Keď sa zamyslíme nad ostatnými atribúty, nie je najmenší dôvod, aby sme ich taktiež umožňovali modifikovať. Študent si za normálnych okolností asi len ťažko zmení pohlavia alebo meno. Bolo by však zároveň vhodné ich vystaviť na čítanie, nemôžeme je teda iba iba nastaviť ako private . V skorších lekciách C # kurzu sme na tento účel používali metódy, ktoré slúžili na čítanie privátnych atribútov. Ich názov sme volili ako VratVek() a podobne. Na čítanie vybraných atribútov vytvoríme tiež metódy a atribúty označíme ako privátne, aby sa nedali modifikovať zvonku. Trieda by novo vyzerala napr. Takto (vynechal som konštruktor a ToString() ):

class Student
{
    private string jmeno;
    private bool muz;
    private int vek;
    private bool plnolety;

    ...

    public string VratJmeno()
    {
        return jmeno;
    }

    public bool VratPlnoletost()
    {
        return plnolety;
    }

    public int VratVek()
    {
        return vek;
    }

    public bool Muz()
    {
        return muz;
    }

    public void NastavVek(int hodnota)
    {
        vek = hodnota;
        // prehodnotenie plnoletosti
        plnolety = true;
        if (vek < 18)
            plnolety = false;
    }


}

Metódy, čo hodnoty len vracajú, sú veľmi jednoduché. Nastavenie veku má už nejakú vnútornú logiku, pri jeho zmene musíme totiž prehodnotiť atribút plnolety . Zaistili sme, že sa do premenných nedá zapisovať inak, ako my chceme. Máme teda pod kontrolou všetky zmeny atribútov a dokážeme na ne reagovať. Nemôže sa stať, že by nám niekto vnútorný stav nekontrolovane menil a rozbil.

Metódam na vrátenie hodnoty sa hovorí Getter a metódam pre zápis setter. Pre editáciu ostatných atribútov by sme urobili jednu metódu EditujStudenta , ktorá by bola podobná konstruktoru. Meno, vek a podobne by sa teda menili pomocou tejto metódy, tam by sme mohli napr. Kontrolovať, či hodnoty dávajú zmysel, opäť by sme odchytili všetky pokusy o zmenu na jedinom mieste.

Ručné písanie Getter a setter je určite veľmi prácne. Nemohol by to urobiť niekto za nás? Áno, C # nám ich vie vygenerovať. Potom už nehovoríme o atribútoch, ale o vlastnostiach. Syntax vlastnosti je veľmi podobná atribútu:

public string Jmeno { get; set; }

Sprvu to vyzerá, ako by sme deklarovali atribút. Meno vlastnosti je však veľkým písmenom, jedná sa totiž o metódu (presnejšie 2 metódy). V zložených zátvorkách potom špecifikujeme, ktoré metódy si prajeme vygenerovať. Za vlastností nepíšeme bodkočiarka! V ukážke vyššie sa vygeneruje setter aj getter, vlastnosť pôjde teda normálne čítať aj modifikovať:

Console.WriteLine(objekt.Jmeno); // čítať
objekt.Jmeno = "Jan Malý"; // zapisovať

Jediný rozdiel oproti atribútu je zvonku v tom, že začiatočné písmeno je veľké. C # v skutočnosti vygeneruje privátnej atribút ak nemu dve metódy, ktoré podľa kontextu volá (spozná podľa situácie či čítame alebo zapisujeme). Keď do vlastnosti nevygeneruje setter, nepôjde meniť zvnútra ani zvonku. Ak si želáme, aby vlastnosť nešla mimo triedu meniť, označíme setter ako privátne:

public string Jmeno { get; private set; }

Tohto budeme hojne využívať a práve takto bude vyzerať väčšina vlastností našich budúcich tried.

Ak si prajeme, aby sa v Getter alebo Setter dialo viac, než len načítanie / zápis hodnoty, môžeme si ho definovať ručne. Ukážme si to na našom príklade s dosiahnutím plnoletosti, ktorá sa musí po zmene veku prehodnotiť:

private int vek;
public int Vek
{
    get
    {
        return vek;
    }
    set
    {
        vek = value;
        // kontrola plnoletosti
        Plnolety = true;
        if (vek < 18)
            Plnolety = false;
    }
}

Sprvu je nutné si vytvoriť privátne atribút vek s malým písmenom, v ktorej bude hodnota v skutočnosti uložené. V Getter a setter potom pracujeme s týmto atribútom, ak použijete v get{} alebo set{} Vek , program sa zacyklí! . Nie je možné definovať len getter alebo setter, buď sa obaja vygenerujú samy alebo oba definujeme ručne. Pre prístup k zadanej hodnote je nám v setter k dispozícii kľúčové slovo value . Takto sa v C # do verzie 3.0 museli definovať všetky vlastnosti, až potom Microsoft zaviedol tzv. Autoimplementaci a skrátený zápis, aký sme si uviedli vyššie. U drvivej väčšiny vlastností totiž v metódach nepotrebujeme žiadnu logiku. S Vek teraz pracujeme opäť rovnako, ako s atribútom, len s veľkým písmenom. Nenápadné priradenie do veku vnútorne spustí ďalšiu logiku k prehodnoteniu vlastnosti Plnolety :

objekt.Vek = 15; // teraz sa zmení aj plnoletosť

Rovnako môžeme pochopiteľne implementovať aj getter a napríklad niečo niekam logovať.

Upravíme si našu triedu Student tak, aby používala vlastnosti. Vyzerala by takto:

class Student
{
    public string Jmeno { get; private set; }
    public bool Muz { get; private set; }
    public bool Plnolety { get; private set; }
    private int vek;
    public int Vek
    {
        get
        {
            return vek;
        }
        set
        {
            vek = value;
            // kontrola plnoletosti
            Plnolety = true;
            if (vek < 18)
                Plnolety = false;
        }
    }

    public Student(string jmeno, bool pohlavi, int vek)
    {
        EditujStudenta(jmeno, pohlavi, vek);
        }

    public void EditujStudenta(string jmeno, bool pohlavi, int vek)
    {
        Jmeno = jmeno;
        Muz = pohlavi;
        Vek = vek;
    }

    public override string ToString()
    {
        string jsemPlnolety = "som";
        if (!Plnolety)
            jsemPlnolety = "nie som";
        string pohlavi = "muž";
        if (!Muz)
            pohlavi = "žena";
        return String.Format("Som {0}, {1}. Je mi {2} rokov a {3} plnoletý.", Jmeno, pohlavi, Vek, jsemPlnolety);
    }

}

To je o veľa lepšie, že? Vlastnosti budeme odteraz používať stále, umožňujú nám totiž objekty dokonale zapouzdřit. V .NET sú všetky verejné atribúty tried vlastnosti (napr. Nám známa vlastnosť Length na string u), platí pravidlo, že čo ide von je vlastnosť, čo sa používa len vo vnútri je privátne atribút. Verejný atribút sa defakto príliš nepoužíva. Celú triedu is ukážkovým programom si samozrejme opäť môžete stiahnuť pod článkom. Kontrolu plnoletosti môžeme z konstruktoru teraz vybrať, akonáhle totiž dosadíme do vlastnosti Vek , nastaví sa plnoletosť sama. Ešte si opäť vyskúšajme problémový príklad:

            Student s = new Student("Pavel Hora", true, 20);
            s.Vek = 15;
            // s.Muz = false; // tento riadok teraz spôsobí chybu a musí byť odobratá
            Console.WriteLine(s);
    class Student
    {
        public string Jmeno { get; private set; }
        public bool Muz { get; private set; }
        public bool Plnolety { get; private set; }
        private int vek;
        public int Vek
        {
            get
            {
                return vek;
            }
            set
            {
                vek = value;
                // kontrola plnoletosti
                Plnolety = true;
                if (vek < 18)
                    Plnolety = false;
            }
        }

        public Student(string jmeno, bool pohlavi, int vek)
        {
            EditujStudenta(jmeno, pohlavi, vek);
        }

        public void EditujStudenta(string jmeno, bool pohlavi, int vek)
        {
            Jmeno = jmeno;
            Muz = pohlavi;
            Vek = vek;
        }

        public override string ToString()
        {
            string jsemPlnolety = "som";
            if (!Plnolety)
                jsemPlnolety = "nie som";
            string pohlavi = "muž";
            if (!Muz)
                pohlavi = "žena";
            return String.Format("Som {0}, {1}. Je mi {2} rokov a {3} plnoletý.", Jmeno, pohlavi, Vek, jsemPlnolety);
        }

    }

A výstup:

Konzolová aplikácia
Som Pavel Hora, muž. Je mi 15 rokov a nie som plnoletý.

Ak celú vlastnosť označíme ako private , nemožno potom setter alebo Getter označiť ako public .

V budúcej lekcii, Dátum a čas v C # , sa pozrieme ako sa v .NET pracuje s dátumom a časom.


 

Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.

Stiahnuť

Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami

Stiahnuté 1373x (26.85 kB)
Aplikácia je vrátane zdrojových kódov v jazyku C#

 

Predchádzajúci článok
Riešené úlohy k 9. lekcii OOP v C # .NET
Všetky články v sekcii
Objektovo orientované programovanie v C #
Preskočiť článok
(neodporúčame)
Dátum a čas v C #
Článok pre vás napísal David Hartinger
Avatar
Užívateľské hodnotenie:
1 hlasov
David je zakladatelem ITnetwork a programování se profesionálně věnuje 15 let. Má rád Nirvanu, nemovitosti a svobodu podnikání.
Unicorn university David sa informačné technológie naučil na Unicorn University - prestížnej súkromnej vysokej škole IT a ekonómie.
Aktivity