čtvrtek 30. září 2010

Parametry v C# 4 lépe a radostněji

csharp Dneska se podívám trochu na novinku v C# 4 a to na parametry metod. Pokud vzpomenu na programování v C++, vybaví se mi možnost definovat parametrům výchozí hodnoty. Když jsem začal programovat v programovacím jazyce C# v dobách kdy vládl .NET Framework 1.0 velmi jsem se po této vlastnosti sháněl a byl jsem zklamán, když jsem zjistil, že není podporována. Nicméně, stačilo několik verzí počkat a tato šikovná vlastnost je na světě a je dotažena k dokonalosti.

O co se vlastně jedná? Jde o možnost kterémukoliv parametru přiřadit výchozí hodnotu, která se použije v okamžiku, pokud není daný parametr při volání metody použit. Pojďme se na to podívat. Vezměme si příklad jednoduché třídy, která bude reprezentovat osobu a bude zapouzdřovat jméno, příjmení, titul před jménem a titul za jménem. Problém je v tom, že ne každá osoba má titul před jménem a ne každý má titul za jménem případně kombinaci těchto. O proti tomu jméno a příjmení má každý. Dříve bychom mohli popsaný problém řešit například takto:

class Osoba
{
public Osoba(string TitulPred, string Jmeno, string Prijmeni, string TitulZa)
{
//inicializace osoby
}

public Osoba(string Jmeno, string Prijmeni, string TitulZa)
: this(string.Empty, Jmeno, Prijmeni, TitulZa)
{
//inicializace osoby probiha pres prvni konstruktor v rade
}

public Osoba(string Jmeno, string Prijmeni)
: this(string.Empty, Jmeno, Prijmeni, string.Empty)
{
//inicializace osoby probiha pres prvni konstruktor v rade
}
//dalsi kod tridy...
}

Jak je vidět z kódu, tak vytváříme jeden plnohodnotný konstruktor, který obsahuje všechny parametry a ostatní konstruktory ho pouze přetěžují a volají tak, že chybějící parametry doplňují přednastavenými hodnotami, v našem případě hodnotou prázdného řetězce. Nyní, když se na daný kód podíváme, musíme si přiznat, že to není nic moc přehledného a v podstatě dva ze tří konstruktorů jsou “zbytečné”. Pro úplnost ještě příklad toho jak vytvářet instance takovéto třídy:

Osoba PrvniOsoba=new Osoba("Jan", "Novák");
Osoba DruhaOsoba=new Osoba("Ing.", "Jan", "Novák");
Osoba TretiOsoba=new Osoba("Jan", "Novák", "DiS.");
Osoba CtvrtaOsoba=new Osoba("Ing.", "Jan", "Novák", "PhDr.");

Všechny tyto způsoby jsou možné a co více, jsou reálné. (Více o titulech naleznete zde)

Co bylo bylo, teď se pojďme podívat jak je to možné řešit dnes. Jako první věc si ukážeme výchozí hodnotu parametru. Zůstaňme u třídy Osoba, pouze ji lehce zmodernizujme:

class Osoba
{
public Osoba(string Jmeno, string Prijmeni, string TitulPred = "", string TitulZa = "")
{
//inicializace osoby
}
//dalsi kod tridy...
}

Přiřazením výchozí hodnoty některým parametrům (těm u kterých to má smysl) jsme snížili potřebný počet konstruktorů na jeden. Možná jste si ale všimli, že se změnilo pořadí parametrů, což je bohužel daň za použití výchozích hodnot parametrů. Je to tak, že prvně se deklarují parametry bez výchozí hodnoty a poté se definují parametry s výchozí hodnotou. Takovéto pořadí se může zdát při volání konstruktoru jako nelogické a nezbývá než s tím souhlasit. Naštěstí i tento stav má řešení, a to pojmenováním parametrů. Fungujete tak, že můžeme u parametru při volání, v našem případě konstruktoru, říci překladači jaký parametr právě přiřazujeme. Celé je to patrné z následujícího příkladu:

Osoba PrvniOsoba = new Osoba("Jan", "Novák");
Osoba DruhaOsoba = new Osoba("Jan", "Novák", "Ing.", "PhDr.");
Osoba TretiOsoba = new Osoba(TitulPred: "Ing.", Jmeno: "Jan", Prijmeni: "Novák");
Osoba CtvrtaOsoba = new Osoba(Jmeno: "Jan", Prijmeni: "Novák", TitulZa: "DiS.");
Osoba PataOsoba = new Osoba(TitulPred: "Ing.", Jmeno: "Jan", Prijmeni: "Novák", TitulZa: "PhDr.");

Pokud se na kód podíváme tak první volání je prosté volání konstruktoru osoby se jménem a příjmením. Druhou osobu voláme se všemi možnými parametry a to tak, že dodržujeme implicitní pořadí jednotlivých parametrů. Od třetí až do páté osoby používáme pojmenované parametry, což je mnohem přehlednější a v případě vynechání některých parametrů i nezbytné.

Za sebe musím říct, že mi tato vlastnost chyběla a jsem velmi rád, že nyní je už k dispozici a věřím že v tomto přesvědčení nejsem sám.

pondělí 6. září 2010

Opakování matka moudrosti, aneb modifikátory přístupu

keys Tak jak už to bývá časem člověk zapomíná a méně používané modifikátory přístupu k objektům jsou přesně adepti na to, aby se nám ztratili z povědomí. Takže jsem se rozhodl si tyto pomocníky zopakovat.

Public

Objekt označený tímto modifikátorem je přístupný odkudkoliv. Takto označený objekt je považován za veřejný. Pokud například označíme metodu třídy modifikátorem public, bude metoda viditelná jak v instanci třídy tak i ve vyděděné třídě.

Private

Objekt označený jako soukromý, přístupný pouze v rámci nadřazeného objektu a není možné k objektu přistupovat od jinud. Například metody třídy označené private nejsou viditelné v instanci třídy a nejsou viditelné ani ve vyděděné třídě.

Protected

Pokud je objekt označen jako chráněný, bude vidět tento objekt pouze v rámci nadřazeného objektu a navíc o proti modifikátoru private bude objekt vidět i ve vyděděném objektu. Takže metoda označená jako protected v bázové třídě bude i v odvozené třídě viditelná ale pouze na úrovni private.

Internal

Tento identifikátor je zajímavý tím, že umožňuje k takto označenému objektu přistupovat v rámci daného sestavení, což může být někdy velmi výhodné. Takže například takto označené enumerátory mohou být přístupné mezi jednotlivými třídami v rámci jedné knihovny, která výsledkem jednoho sestavení. Modifikátor internal se dá také kombinovat jako například protected internal.

Static

Objekty které mají modifikátor přístupu static, jsou zvláštní tím, že k jejich používání není třeba vytvářet instanci objektu a z toho vyplívá i chování objektu. Pokud máme v nějaké třídě například statickou proměnou, a přistupujeme k ní, je společná všem, kteří k ní přistupují.

Abstract

Tento modifikátor říká, že objekt je určen jako řekněme generická šablona pro další odvozování objektů. To znamená, že z objektu není možné vytvářet instance, pouze z jeho následníků. Například, vytvoříme-li si abstraktní třídu člověk která obsahuje obecné metody společné všem lidem. Z této abstraktní třídy můžeme odvodit třídu zaměstnanec, která má navíc metody potřebné pro zaměstnance. Dále pak můžeme odvodit třídu vedoucí, která bude obsahovat navíc metody potřebné pro vedoucího. A z těchto odvozených tříd můžeme vytvářet instance a ty používat.

Virtual

Objekty označené jako virtual jsou určené k možnému přepsání za pomoci modifikátoru override. Nejčastěji je toto použito u metod třídy, z níž se odvozují další třídy a pokud v odvozené třídě je třeba danou metodu přepsat, za předpokladu, že v bázové třídě je použito modifikátoru virtual, je možné tak učinit s tím, že volání a návratová hodnota metody zůstanou stejné a změní se pouze obsah.

Override

Tímto modifikátorem se označují objekty, která nahrazují bázové metody označené jako virtual, jak je řečeno o odstavec výše.

Extern

Toto označení se používá u metod, které jsou implementovány externě v jiném programovacím jazyce.

Sealed

Tento speciální modifikátor ve spojení s override umožňuje přepsat bázovou metodu označenou virtual, ale v dalších odvozeních už tato metoda není přepsatelná, je takzvaně zapečetěná.