Třídy

4. díl - Třídy

Tomáš Herceg       09.06.2009       C#, VB.NET, .NET       24655 zobrazení

V tomto díle se podrobněji podíváme a to, jak vypadají třídy, jak se s nimi pracuje, jak fungují konstruktory a jaký je rozdíl mezi instančními a statickými metodami. Nemalou část povídání strávíme popisem toho, jak fungují vlastnosti a proč bychom je měli používat.

V minulém díle jsme si povídali o datových typech, vysvětlili jsme si, co jsou to typy hodnotové a referenční. Dnes se až na pár výjimek budeme bavit o typech referenčních, kterýmižto jsou především třídy.

Nebudeme zde trávit čas vysvětlováním, co je to třída, to už byste měli vědět a znát. Pod tomu tak není, navštivte článek Úvod do objektově orientovaného programování, který se nám zde na webu válí.

Chceme-li deklarovat nějakou vlastní třídu, napíšeme toto. Vše, co se týká dané třídy, píšeme dovnitř.

Kód v jazyce Visual Basic .NET
    Class MojeTrida

    End Class

Kód v jazyce C#

    class MojeTrida
    {
    }

Kde se deklarace třídy může vyskytovat?

  • uvnitř jmenného prostoru (v bloku namespace) - pak je třída zařazena do tohoto jmenného prostoru
  • mimo jmenný prostor - pak je třída zařazena do výchozího jmenného prostoru (nastavuje se ve vlastnostech projektu)
  • uvnitř třídy - třída se vztahuje k rodičovské třídě, její celý název zahrnuje namespace a název rodičovské třídy

Konvence

V .NETu je jedno, v jakém souboru se která deklarace vyskytuje. Např. v Javě nebo třeba v ActionScriptu toto neplatí, třída tam musí být definována v souboru se stejným názvem (musí být dodržena i jejich velikost).

Jazykům C# i VB.NET je to úplně jedno, můžete mít v jednom souboru více tříd, od verze 2.0 .NET Frameworku je povoleno i jednu třídu rozdělit do více souborů (tzv. partial classes). To se hodí v případě, že část třídy generuje např. Visual Studio, zatímco druhou část píše člověk a není vhodné, aby psal do stejného souboru, jelikož by mu to vývojové prostředí mohlo přepsat. Tento přístup se používá velmi často. Pro vytvoření parciální třídy stačí před slovo class napsat klíčové slovo partial (ve VB.NET i v C#).

Vnořené třídy (třída ve třídě) se obecně moc nepoužívají, ale to je spíš záležitost zvyku a osobních preferencí.

Vytváření instancí tříd

Novou instanci třídy můžeme vytvořit použitím klíčového slova new.

Kód v jazyce Visual Basic .NET
Dim instance As MojeTrida = New MojeTrida()         'plný zápis
Dim instance As New MojeTrida()                     'zkrácený zápis

Kód v jazyce C#

MojeTrida instance = new MojeTrida();

Co se vlastně stane? Založí se nová proměnná typu MojeTrida a ihned se do ní přiřadí instance třídy MojeTrida. Volání new MojeTrida() zavolá výchozí konstruktor pro danou třídu a vrátí nově vytvořenou instanci. Při vytvoření instance třídy jsou všechny proměnné uvnitř třídy automaticky zinicializovány na své výchozí hodnoty (číselné typy na 0, boolean na false, referenční typy na null). To je rozdíl oproti lokálním proměnným v metodách, ty jsou ve VB.NET inicializované (kvůli zpětné kompatibilitě), v C# ne a kompilátor vám je ani nedovolí použít, dokud do nich něco nepřiřadíte.

Konstruktor

Konstruktor je speciální metoda, která slouží pro inicializaci třídy. Každá třída v .NETu má svůj výchozí konstruktor. Pokud v deklaraci třídy sami neuvedeme žádný konstruktor, bude výchozí konstruktoru (bez parametrů) kompilátorem vygenerován za nás a “nebude dělat nic” (je to jako kdybychom ho nadeklarovali a nic dovnitř nenapsali). Pokud při založení instance třídy chceme dělat něco my, musíme výchozí konstruktor specifikovat.

Konstruktor se deklaruje v obou jazycích značně odlišně. Ve VB.NET to je metoda, která se jmenuje New, v C# je to metoda, která se jmenuje stejně jako třída a nepíšeme u ní návratový typ (ani void ani cokoliv jiného).

Kód v jazyce Visual Basic .NET
Class MojeTrida

    Public Sub New()

    End Sub

End Class

Kód v jazyce C#

class MojeTrida
{

    public MojeTrida()
    {
    }

}

Modifikátory přístupnosti

V tomto i v minulém díle jsem používal slova public, private atd., ale blíže jsme si nevysvětlili, co vlastně znamenají. Zde u konstruktoru máme klíčové slovo public, které říká, že konstruktor třídy je možné volat zvenčí (z metody mimo tuto třídu). Jak to vlastně je?

VB.NET C# Popis
Public public Přístupné odkudkoliv
Protected Friend protected internal Přístupné odkudkoliv v rámci assembly
Přístupné z potomků této třídy
Friend internal Přístupné odkudkoliv v rámci assembly
Protected protected Přístupné z potomků této třídy
Private private Přístupné jen z aktuální třídy

Potřebná přístupnost pro práci s metodou

Na obrázku je vše vidět. Fialové krabičky jsou třídy, ze kterých chceme volat zelenou metodu. Vidíme, jaká oprávnění potřebujeme, abychom mohli třídu zavolat. Je nutno podotknout, že pokud stačí přístupnost private a máme public (tedy něco, co je v tabulce na vyšším řádku), ničemu to nevadí. Horší by to bylo obráceně.

Pokud voláme metodu z té samé třídy, stačí nám, aby metoda byla private. Pokud voláme metodu ze třídy B, která dědí (je potomek) třídy A, potřebujeme alespoň protected. Pokud voláme ze třídy, která k A nemá žádný vztah, ale je ve stejné assembly, pak nám stačí Friend / internal. Pokud voláme metodu z třídy v jiné assembly, která ale dědí třídu A, stačí nám Protected Friend / protected internal. Pokud jsme v jiné assembly a nemáme s třídou A žádný vztah (nejsme ani syn, ani strýček, ani babička kočky její sestry), potřebujeme přístup public.

Ve většině případů alespoň ze začátku vystačíme s public, protected a private. Relativně často se také používá Friend / internal, zvlášť když píšete nějakou knihovnu a máte v ní pomocné třídy, které potřebujete všude, ale nechcete je publikovat ven, poslední variantu Protected Friend / protected internal jsem viděl v praxi jen párkrát a kdyby tam bylo public, vůbec nic by se nestalo. Ne, že by byla k ničemu, ale moc často ji nepotkáte.

Zpět ke konstruktorům

Našemu výchozímu konstruktoru jsme dali modifikátor public, tím pádem bude veřejně dostupný a bude tedy možné vytvářet instance této třídy kdekoliv. Pokud bychom mu neuvedli nic, byl by private, proměnné a metody uvnitř třídy jsou ve výchozím stavu private. Nebylo by možné vytvořit instanci jinde než v nějaké metodě, která je v této třídě. To se občas využívá, především k implementaci některých návrhových vzorů, např. singleton. Ve většině případů je ale konstruktor veřejný.

Kromě výchozího konstruktoru můžeme mít také konstruktory jiné, takové, které mají parametry. To se používá velmi často - některé třídy v mnoha aplikacích nemají žádnou promyšlenou funkcionalitu a slouží pouze jako reprezentace dat (např. třída Zamestnanec může sloužit jen k reprezentaci záznamu z databáze, bude mít vlastnosti Jmeno, Prijmeni atd.). Hodí se mít možnost vytvořit takovou třídu v kódu na jeden řádek.

To můžeme zařídit pomocí konstruktoru s parametry.

Kód v jazyce Visual Basic .NET

Class Zamestnanec

    Dim jmeno, prijmeni As String

    Public Sub New(ByVal jmeno As String, ByVal prijmeni As String)
        Me.jmeno = jmeno
        Me.prijmeni = prijmeni
    End Sub

End Class
Kód v jazyce C#
class Zamestnanec
{

    string jmeno, prijmeni;

    public Zamestnanec(string jmeno, string prijmeni)
    {
        this.jmeno = jmeno;
        this.prijmeni = prijmeni;
    }
}

Tohle je velmi typické použití konstruktoru s parametry a můžeme jej potkat velmi často. Předají se mu parametry, jejichž hodnoty pouze nastavíme do členských položek třídy. Všimněte si klíčového slova Me resp. this, kterým ukazujeme na aktuální instanci třídy a rozlišujeme mezi parametrem metody a proměnnou třídy. Kdyby se proměnné třídy jmenovaly jinak než parametry konstruktoru, nemuseli bychom toto klíčové slovo použít a jít přímo. Pokud se ale jmenují stejně, bez použití Me resp. this se bere ta proměnná, která je “blíž” (nejprve lokální proměnné, pak proměnné uvnitř třídy, kde jsme).

Vytvoření instance pak bude vypadat třeba takto:

Kód v jazyce Visual Basic .NET

Dim zam As New Zamestnanec("Tomáš", "Herceg")
Kód v jazyce C#
Zamestnanec zam = new Zamestnanec("Tomáš", "Herceg");

Volání jiných konstruktorů

Často potřebujeme konstruktory přetěžovat - podle počtu a typu předaných parametrů rozlišit mezi příslušnými konstruktory. Toto funguje samozřejmě při volání jakékoliv metody, můžeme udělat více metod se stejným názvem, které se budou lišit jen počtem a typy argumentů. Konstruktor je speciální metoda, ale funguje to úplně stejně. O tom, jak přetěžování metod přesně funguje a jaká jsou tam pravidla, si povíme v některém z příštích dílů.

Takto například uděláme možnost volitelně zaměstnanci předat jeho věk. Protože se jménem a příjmením budeme dělat to samé, co o konstruktor výše, bylo by škoda opisovat ten kód znovu. My ale můžeme z jednoho konstruktoru zavolat konstruktor jiný a předat mu parametry. V každém jazyce se to dělá trochu jinak, princip je ale stejný:

Kód v jazyce Visual Basic .NET

Class Zamestnanec

    Dim jmeno, prijmeni As String
    Dim vek As Integer

    Public Sub New(ByVal jmeno As String, ByVal prijmeni As String)
        Me.jmeno = jmeno
        Me.prijmeni = prijmeni
    End Sub

    Public Sub New(ByVal jmeno As String, ByVal prijmeni As String, ByVal vek As Integer)
        MyClass.New(jmeno, prijmeni)   'musí být na začátku konstruktoru, jinak se kompilátor vztekne!
        Me.vek = vek
    End Sub

End Class

Kód v jazyce C#

class Zamestnanec
{

    string jmeno, prijmeni;
    int vek;

    public Zamestnanec(string jmeno, string prijmeni)
    {
        this.jmeno = jmeno;
        this.prijmeni = prijmeni;
    }

    public Zamestnanec(string jmeno, string prijmeni, int vek)
        : this(jmeno, prijmeni)
    {
        this.vek = vek;
    }
}

Ve VB.NET jiný konstruktor zavoláme přes klíčové slovo MyClass, v C# musíme volání zapsat již do deklarace metody za dvojtečku.

Poznámka: Pokud nyní zkusíte vytvořit instanci třídy Zamestnanec bez parametru, nepůjde to. Výchozí konstruktor třída nemá, kompilátor jej vygeneruje pouze v případě, že neuvedeme žádný konstruktor. Zde jsme ale konstruktory uvedli, výchozí mít třída nebude.

Metody uvnitř tříd

Jak se deklarují metody jsme již viděli v předminulém dílu a není k tomu moc co dodat. Každá metoda musí být uvnitř nějaké třídy. Jen pro připomenutí ukážeme syntaxi:

Kód v jazyce Visual Basic .NET

    Public Sub Vypis()
        Console.WriteLine("Jméno: " & jmeno)
        Console.WriteLine("Příjmení: " & prijmeni)
    End Sub

Kód v jazyce C#

    public void Vypis()
    {
        Console.WriteLine("Jméno: " + jmeno);
        Console.WriteLine("Příjmení: " + prijmeni);
    }

Tato metoda vypíše na konzoli informace o zaměstnanci, tedy jeho jméno a příjmení. Nic světoborného.

Statické versus instanční

Nyní je nutné vysvětlit si pojmy statické a instanční. Abychom mohli zavolat naši metodu Vypis, potřebujeme k tomu instanci třídy Zamestnanec. Metoda se vztahuje ke konkrétní instanci - je tedy instanční. Metodu voláme vždy na proměnné (typu Zamestnanec).

Naproti tomu statické metody jsou sice deklarovány uvnitř třídy, ale mají něco společného s třídou a ne s konkrétní instancí. Velmi často slouží jako metoda, která dostane parametry, a vrátí již hotovou instanci třídy, která je nějak předpřipravená. Hodí se to v případech, kdy vytvoření instance třídy není úplně triviální záležitost a je k tomu třeba víc operací. Samozřejmě možných využití je více.

Statické metody voláme ne přes proměnnou (přes konkrétní instanci), ale přes název třídy. Pokud chceme metodu nadeklarovat jako statickou, přidáme do názvu slovo static v C# a Shared ve VB.NET (pozor! VB.NET má slovo Static také, ale to slouží k jinému účelu).

Kód v jazyce Visual Basic .NET
Public Class A
    Public Sub Instancni()
    End Sub

    Public Shared Sub Staticka()
    End Sub
End Class
Dim _a As New A()

' přístup přes "proměnnou"
_a.Instancni()

' přístup přes "datový typ"
A.Staticka()

Kód v jazyce C#

public class A
{
    public void Instancni() { }
    public static void Staticka() { }
}  
A a = new A();

// přístup přes "proměnnou"
a.Instancni();

// přístup přes "datový typ"
A.Staticka(); 

Instanční nebo statické může být prakticky vše, co je uvnitř třídy - proměnné, vlastnosti, metody atd. Z instančních metod můžeme přistupovat ke statickým proměnným, opačně to jde jen pokud máme nějakou instanci třídy. V instanční metodě můžeme napsat rovnou volání Staticka() tak, jak leží a běží, a bude to fungovat. Ve statické metodě ale Instancni() napsat nemůžeme, kompilátor nám vynadá, že přistupujeme k instanční položce.

Proměnné uvnitř tříd

Pokud máte uvnitř třídy proměnné, měly by být nejvýše protected. Žádná proměnná by neměla být viditelná mimo třídu, ve které se používá. Má to mnoho důvodů a je dobré to dodržovat.

Asi nejhlavnějším důvodem je možnost narušení konzistence stavu objektu. Máme například třídu, která reprezentuje seznam něčeho a celkem logicky si v nějaké proměnné pamatuje počet položek. Někdo, kdo tuto třídu používá, potřebuje venku počet položek číst, takže vcelku přímočarým řešením je udělat proměnnou Count veřejnou a je to.

Pak ale přijde někdo, kdo neví, jak třída uvnitř funguje (což je u větších projektů naprosto běžná věc, každý píše svoji část a ostatní lidé hotové třídy jen používají). Řekne si třeba “chci seznam pro 15 položek, aha jasně, tak nastavím Count na 15 a je to”. To je ještě relativně v pořádku, program spadne a nebude fungovat. Horší to ale bude, až někdo udělá podobnou chybu, vynuluje nějakou veřejně dostupnou proměnnou, což může to mít dalekosáhlé důsledky. Například to někomu to smaže výplatu a on vás pak přijde defenestrovat, což tak trochu dovede zkazit odpoledne.

Vlastnosti (properties)

Elegantním řešením, jak zpřístupnit proměnnou ven ze třídy (protože to je dost často potřeba) a nedělat kvůli tomu separátní metodu, je použít vlastnosti. Vlastnost je povětšinou dvojice metod (getter a setter), které se navenek chovají jako proměnná (a v drtivé většině případů se používají i k řízení přístupu k proměnné). Je nutné si ale uvědomit, že vlastnosti nemusí být vázány na konkrétní proměnnou, přestože to tak v drtivé většině případů bývá.

Zde je první typický model použití vlastnosti - vlastnost řídí přístup k proměnné a zpřístupňuje ji ven ze třídy. Možná si říkáte, že je to zbytečné, a akorát to zpomaluje (ve skutečnosti ne, JIT kompilátor to vyoptimalizuje - většinou). Ve skutečnosti to je velmi užitečné. Kdykoliv v budoucnu bude potřeba přidat do setteru nějaké validace (aby tam někdo nedal hodnotu null resp. Nothing), anebo v getteru ošetřit nějaké speciální případy (např. lazy inicializace viz dále). Pokud byste přistupovali k proměnné, tak snadno se to nepředělá, pokud máte vlastnost, velmi jednoduše do ní můžete příslušný kód doplnit.

Kód v jazyce Visual Basic .NET
    Public Property Jmeno() As String
        Get
            Return _jmeno
        End Get
        Set(ByVal value As String)
            _jmeno = value
        End Set
    End Property

Kód v jazyce C#

    public string Jmeno
    {
        get { return jmeno; }
        set { jmeno = value; }
    }

Pokud chcete do vlastnosti něco přiřadit, zavolá se setter a provede se kód v něm. Pokud chcete hodnotu vlastnosti číst, zavolá se naopak getter. S vlastnostmi pracujeme úplně stejně, jako kdyby to byla proměnná ve třídě.

Všimněte si, že ve VB.NET musíme před název proměnné dát znak podtržítko. Resp. nemusíme, můžeme tu proměnnou pojmenovat úplně jinak, ale je to taková konvence a je velmi dobré ji dodržovat, abyste byli kompatibilní se zbytkem světa. Ve VB.NET totiž nezáleží na velikosti písmen a jmeno je to samé co Jmeno (Visual Studio samo písmena zvětší a zmenší tak, aby to všude vypadalo stejně).

Naproti tomu v C# bývá zvyklost pojmenovávat proměnnou stejně jako vlastnost, akorát vlastnost začíná velkým písmenem. Přestože to jde, neměli byste nikdy dovnitř třídy dávat veřejné názvy lišící se jen velikostí písmen, protože pak je tato třída prakticky nepoužitelná z jiných jazyků, které na velikost písmen z vysoka kašlou. To ale není tento případ, ven je vidět jen vlastnost, proměnná ne.

Druhým velmi častým případem, kdy se vlastnosti používají, je tzv. lazy inicializace. Hodí se to například v případě, kdy potřebujete načíst třeba konfiguraci aplikace, což může trvat poněkud déle, a nechcete tím zdržovat start aplikace, načtete ji až v momentě, kdy ji opravdu použijete, třeba v okamžiku zobrazování okna s nastaveními. Navíc ji chcete načíst jen jednou a ne pokaždé.

Kód v jazyce Visual Basic .NET
Public Class Utils

    Private Shared _config As Object
    Public Shared ReadOnly Property Configuration() As Object
        Get
            If _config Is Nothing Then InitConfiguration() 'pokud ještě konfigurace není načtená, načíst ji
            Return _config
        End Get
    End Property
    ...
End Class

Kód v jazyce C#

public class Utils
{
    private static object config;

    public static object Configuration
    {
        get 
        {
            if (config == null) InitConfiguration();    // pokud ještě konfigurace není načtená, načíst ji
            return config;
        }
    }
... }

Naše vlastnost je nyní readonly. Ve VB.NET se to zařídí tak, že před klíčové slovo Property přidáte slovo Readonly a neuvedete sekci Set. V C# stačí neuvést sekci set.

Jak se to bude používat? Jednoduše, je to statické, takže v aplikaci napíšete Utils.Configuration.něco atd. Při prvním použití se konfigurace načte, při dalších se již načtená konfigurace rovnou vrátí. Podotýkám, že metoda InitConfiguration musí být také statická, definovaná ve třídě Utils a načtenou konfiguraci musí uložit do proměnné config resp. _config.

Existují dokonce i writeonly properties, které nemají getter, jen setter. K čemu jsou, to mi ještě nikdy nikdo nevysvětlil, v životě jsem je neviděl.

Novinky v .NET Frameworku 3.5 a 4.0

Malá odbočka, která se ale vyplatí. V .NET Frameworku veze 3.5, kde se objevila nová verze jazyka C#. Ta přinesla tzv. auto-implemented properties, což je zkrácená syntaxe pro zápis vlastností. Vychází z faktu, že většina vlastností nedělá nic jiného, než zpřístupnění nějaké proměnné (této proměnné se také říká backing field). Proto se umožnilo v C# zkrácení syntaxe zápisu vlastností.

Kód v jazyce C#

string Jmeno { get; set; }

Jak se to chová? Úplně stejně jako ukázka kódu pod tímto odstavcem, akorát se nemusíme patlat s tou privátní proměnnou. Vygeneruje ji za nás kompilátor. Výhodou je, že z několikařádkového zápisu se stal zápis na jeden řádek, který je přehlednější a v případě, že budeme do vlastnosti potřebovat přidat nějaké validace nebo něco, snadno jej překlopíme do “ukecané” verze. Oba zápisy jsou ekvivalentní (v tom druhém chybí akorát deklarace privátní proměnné jmeno).

    public string Jmeno
    {
        get { return jmeno; }
        set { jmeno = value; }
    }

Ve VB.NET tato možnost zatím není, bude v .NET Frameworku verze 4.0, který mimo jiné přinese novou verzi jazyka Visual Basic, a to verzi 10. V době psaní tohoto článku je .NET 4.0 ještě v betaverzi, následující ukázka nebude fungovat ve Visual Studiu 2008 a starších verzích.

Kód v jazyce Visual Basic .NET

Public Property Jmeno As String

Co je výhodou, automatické vlastnosti ve VB.NET budou umět na rozdíl od C# počáteční inicializaci. Pokud za daný kód napíšete = “Tomáš”, bude vlastnost automaticky inicializována na příslušnou hodnotu.

Řízení přístupu ke getteru a setteru

Jak v automatické verzi v C#, tak v té rozšířené můžete specifikovat modifikátor přístupnosti buď pro getter, nebo pro setter (ne pro oba najednou; pro ten, pro nějž to neuvedete, se použije modifikátor přístupu celé vlastnosti).

Zvláště u automatických vlastností se hodí velmi často toto nastavení:

Kód v jazyce Visual Basic .NET

    Public Property Jmeno As String
        Get
            Return _jmeno
        End Get
        Private Set(ByVal value As String)
            _jmeno = value
        End Set
    End Property

Kód v jazyce C#

    string Jmeno { get; private set; }

Tento přístup se velmi často používá v případě, že potřebujete zevnitř třídy vlastnost nastavit, ale ostatní ji mají jít jen pro čtení. Aby to šlo i s automatickými vlastnostmi, je možnost pro setter nastavit oprávnění private, díky kterému zvenku vlastnost změnit nepůjde a zevnitř ano. Ve VB.NET tohle u automatických vlastností pravděpodobně nepůjde. Jak to bude ve finální verzi mi není známo.

Object initializers

Pokud vytváříte nějakou promyšlenou datovou třídu, která má některé vlastnosti nepovinné, pravděpodobně brzy skončíte u toho, že budete mít 10 přetížených konstruktorů, které se budou lišit počtem parametrů. Desátý bude volat devátý, devátý volá osmý atd., přičemž každý má právě o jeden parametr víc než ten předchozí. To není příliš elegantní, proto v C# 3 ve ve VB9 přišly tzv. object initializers.

Použití je velmi jednoduché a je to opět jen zkrácení syntaxe.

Kód v jazyce Visual Basic .NET

        'první způsob
        zam = New Zamestnanec()
        zam.Jmeno = "Tomas"
        zam.Prijmeni = "Herceg"
        zam.Vek = 21

        'druhý způsob - použití object initializers
        zam = New Zamestnanec() With {.Jmeno = "Tomas", .Prijmeni = "Herceg", .Vek = 21}

Kód v jazyce C#

        // první způsob
        zam = new Zamestnanec();
        zam.Jmeno = "Tomas";
        zam.Prijmeni = "Herceg";
        zam.Vek = 21;

        // druhý způsob - použití object initializers
        zam = new Zamestnanec() { Jmeno = "Tomas", Prijmeni = "Herceg", Vek = 21 };

První a druhý způsob jsou naprosto ekvivalentní. Jmeno, Prijmeni a Vek musí být vlastnosti, na proměnné to nefunguje! Navíc třída Zamestnanec musí mít v tomto případě výchozí konstruktor (obecně ten, který použijeme při volání před složenou závorkou).

Závěrem

To je pro tento díl vše. Nedostali jsme se k mnoha věcem, například k dědičnosti, rozhraním atd., ale to si vynahradíme někdy příště.

 

hodnocení článku

1 bodů / 1 hlasů       Hodnotit mohou jen registrované uživatelé.

 

Všechny díly tohoto seriálu

7. Rozhraní 19.07.2010
6. Dědičnost - dokončení 01.01.2010
5. Dědičnost 09.09.2009
4. Třídy 09.06.2009
3. Datové typy 05.05.2009
2. Základní elementy VB.NET a C# 18.04.2009
1. Úvod do .NET Frameworku 03.04.2009

 

Mohlo by vás také zajímat

Genericita, rozhraní a dědičnost

Jazyk C# je multiparadigmatický, což v praxi znamená, že v něm můžeme dělat hodně věcí. Jak ale do sebe jednotlivá paradigma zapadají? Co se hezky doplňuje a co není vzájemně kompatibilní? V tomto článku chci popsat, jak se chová IEquatable vzhledem k dědičnosti typu T.

Jednoduchý scheduler v .NETu

Asi to znáte – máte nějaký složitější systém na zpracování velkého objemu dat a čas od času potřebujete vykovat nějakou automatizovanou údržbu – typicky smazat všechny položky starší než několika dní. Možností, jak toho dosáhnout, je hodně. Snažil jsem se vymyslet něco jednoduchého a efektivního.

představení nového seriálu o ASP .net MVc - from zero to hero

 

 

Nový příspěvek

 

Diskuse: Třídy

Ahoj, začínám s .Netem, takže se omlouvám, ale zkuste mi vysvětlit, jak mohu z vnitřní třídy číst / nastavovat proměnné vnější třídy:


Class HlavniTrida
{

    long pozice_x;
    long pozice_y;
    
    public HlavniTrida()
    {
    }
    
    // Set: x=20 ; y=30
    public void nastavPozici(long x, long y)
    {
      pozice_x = x;
      pozice_y = y;
    }
    
            Class VnitrniTrida
            {
            
              // ??? má to tu být deklarováno nebo ne?
              // chci sdílet (get / set) hodnoty z vnější třídy
              long pozice_x;
              long pozice_y;

              public VnitrniTrida()
              {
              }
              
              // Set: x=2 ; y=3
              public void posunObjektu(long x, long y)
              {
                pozice_x = pozice_x + x;
                pozice_y = pozice_y + y;
                
                // Jak udělat to, abych pracoval s vnější proměnnou?
                // Očekávám výsledek:
                // pozice_x = 22
                // pozice_y = 33
                
              }
              
              public string pozice_Vrat()
              {
                return string.format("X = {0} a Y = {1}",pozice_x,pozice_y);
                // Vrátí: "X = 22 a Y = 33"
              }
              
            } // End Class VnitrniTrida
    
} // End Class HlavniTrida

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Třídy

Dobrý den,

rozumím tomu dobře tak, že pokud chci vytvořit třídu, kterou bude moci využívat (vytvářet) pouze jedna jediná jiná třída ze stejného souboru, pak musím vytvořit třídu s konstruktorem Friend, případně třídu Friend Class něco?

Díky

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Třídy

Zdravím. ;)

Napadla ma otázka ohľadom C# a C++, ale i keď je tento web orientovaný na VB, mohli by ste mi ju zodpovedať. :)

V C++ sa dajú metódy definovať dvoma spôsobmi. Inline a outline (outline asi nie je správne pomenovanie).

//INLINE

class A()

{

public void a()

{ //niečo }

};

//OUTLINE

class A()

{

public void a();

};

public void A::a()

{ //niečo };

Rozdiel medzi nimi je tuším v tom, že jeden spôsob je rýchlejší a druhý pamäťovo úspornejší.

OTÁZKA: Má niečo také aj C#, alebo ide o niečo, čomu sa neoplatí v tejto dobe už venovať pozornosť.

Ďik ;))

nahlásit spamnahlásit spam 0 odpovědětodpovědět

V rychlosti programu ani v paměťové náročnosti rozdíl opravdu není, oba zápisy jsou analogické. Jen C++ má to debilní dělení na hlavičkové soubory a soubory s kódem, takže hlavička typicky obsahuje jen deklarace a cpp soubor pak samotný kód. Pokud ale používáte šablony, tak stejně musíte vše dát do hlavičky, takže to je jedno.

Outline zápis je mimořádně otravný, protože deklarace metody je opakující se kód - potřebujete přidat parametr a musíte to psát na 2 místa.

C# ani VB.NET outline zápisy nepodporují, není k tomu žádný důvod - metody zapíšete pouze dovnitř bloku class. A pokud chcete jednu třídu rozdělit do více souborů, použijete klíčové slovo partial. Nic víc v tom není.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Dík za rýchlu odpoveď. ;)

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Třídy

Nádhera, konečně pořádně chápu třídy.. :-) Teda aspoň, skvěle pro začátek.. Skvělej díl, dík! :-)

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Třídy

Ahoj, použití přístupu k proměnným (getter a setter) mi běhá ok. Ale teď jsem zasekl na tom, že ve třídě definuji vlastní strukturu a není mi úplně jasné, jak k ní přístupovat ?

    Private Enum PinFunc

        DigitalInput = 1
        DigitalOutput = 2
        AnalogOutput = 8
        AnalogInput = 4

    End Enum
    Private Structure _Pins
        Dim _Value As UShort
        Dim _Func As PinFunc
    End Structure
    Private _PinA As _Pins
    Private _PinB As _Pins

Stačí nakopnout :-)

Díky

J.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Jestli potřebujete nastavovat struktury tak:

Property Value As UShort
 Get
  Return _PinA._Value
 End Get
 
 Set(...)
  _PinA._Value = value
 End Set
End Property

a takhle to udělat i pro _PinA._Func a _PinB

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Diskuse: Třídy

VB predsa nie je CASE SENSITIVE, už pri zápise by nám kompilátor pravdepodobne škaredo vynadal:


Dim a As New A()

' přístup přes "proměnnou"
a.Instancni()

' přístup přes "datový typ"
A.Staticka()

nahlásit spamnahlásit spam 3 / 3 odpovědětodpovědět

Samozřejmě máte pravdu, díky za upozornění.

nahlásit spamnahlásit spam 2 / 2 odpovědětodpovědět

Diskuse: Třídy

Kde byl tento clanek, kdyz jsem se pred nekolika lety ucil OOP... ;-(

Pro zacatecniky je uplne genialni

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Třídy

Dobrý článek, jen by zde mohla být i zmínka o destruktoru třídy, který se používá například při implementaci vzoru Dispose-Finalize.

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Chtěl jsem to zařadit, ale vhodnější to bude až společně s IDisposable a rozhraní jsem v tomto seriálu ještě neprobíral.

nahlásit spamnahlásit spam 0 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.

Nyní zakládáte pod článkem nové diskusní vlákno.
Pokud chcete reagovat na jiný příspěvek, klikněte na tlačítko "Odpovědět" u některého diskusního příspěvku.

Nyní odpovídáte na příspěvek pod článkem. Nebo chcete raději založit nové vlákno?

 

  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:
Heslo:

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback