IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
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í.

Novinky v C # 6

20. júla 2015 sa odohralo hneď niekoľko vecí. Vyšlo nové Visual Studio 2015, ďalej C# 6 a nakoniec i .NET 4.6, ktorý je prichystaný na príchod Windows 10. My sa ale zameriame iba na novú verziu C #.

Predtým, než prejdeme k samotnému C #, by som rád spomenul Project Roslyn. Jedná sa o open-source kompiler pre Windows i Linux, určený pre C# a VB.NET. Zaujímavosťou je, že je napísaný v rovnakom jazyku, ktorý prekladá, teda C# Roslyn kompiler je napísaný v C# a cez Common Language Runtime sa sám prekladá Just In Time.

Teraz už k samotnému C #. Na rozdiel od predchádzajúcich verzií nepridáva nové technológie. Pri pohľade do histórie, C# 2 pridal do jazyka možnosť generického programovania, C# 3 lambda výrazy a posledná verzia C# 5 bola veľa zameraná na asynchrónne programovanie. Aktuálna verzia C# 6 sa zameriava skôr na čitateľnosť, udržiavateľnosť a správu kódu. Pri pohľade na jednotlivé body sa nám môže zdať, že sú nevýrazné a niekedy nás dokonca prekvapí, že v predchádzajúcej verzii neboli. Tak schválne, skúšali ste niekedy použiť asynchrónne metódy v catch alebo finally bloku? Vo výsledku ale kód sprehľadní, často skráti a bude lepšie udržiavateľný. Teraz už sa poďme pozrieť na jednotlivé body.

Návrh triedy

Read-only auto properties

Koľko z nás už popísalo nasledujúcu časť kódu, keď potrebovali implementovať read-only properties?

//první varianta
private readonly int _OldStyleReadonly;
public int OldStyleReadonly
{
    get { return _OldStyleReadonly; }
}

//druhá varianta
public int AnotherReadonly {get; private set; }

Teoreticky by sme mohli readonly premennú vytvoriť ako verejnú, ale čistejšia je predsa len vytvoriť ju súkromnú a pristupovať k nej pomocou Getter. Napríklad ak by sme neskôr názov premennej zmenili, nemuseli by sme prepisovať celý program. C# 6 prináša zmenu, vďaka ktorej môžeme definovať property iba s auto Getter. Takéto property bude musieť byť priradená hodnota priamo (alebo v konstruktoru) a nie je možné ju z vonku zmeniť. Na rozdiel od druhého spôsobu zápisu nemožno hodnotu zmeniť ani v metódach triedy. Zápis vyzerá nasledovne.

public int NewStyleReadonly { get; } = 20;

Lambda-like tela metód

Nová verzia C# tiež pridala Lamba-like tela funkcií. Opäť si uvedieme pôvodné príklad a následne aj nový zápis.

class Point
{
    int x;
    int y;
    Point(int x, int y)
    {
        this.x = x;
        this.y = y;
    }

    //Old way
    public int OldX
    {
        get { return x; }
    }
    public int OldY
    {
        get { return y; }
    }
    public double OldDistanceFromZero()
    {
        return Math.Sqrt(x*x*+y*y);
    }

    //New way
    public int NewX => x;
    public int NewY => y;
    public double NewDistanceFromZero() => Math.Sqrt(x*x+y*y);
}

Sami vidíte, o koľko sa zápis skrátil a výsledok je úplne rovnaký. Podmienkou tohto zápisu je, že musí nasledovať iba jeden príkaz. Ak sa pokúsime použiť zložené zátvorky, a teda napísať aj viac príkazov za seba, kompilátor nahlási chybu a program sa nezkompiluje. To obmedzuje písanie dlhých blokov kódu, ktoré by na prehľadnosti naopak ubrali.

Práca sa STRING

Operátor nameof

Do novej verzie sa tiež dostal nový operátor nameof. Ten nahrádza premennú jej názvom. Využijeme to napríklad pri generovaní JSON alebo u binding, pri ktorom potrebujeme mať zviazanú premennú v triede s výstupom, kde je premenná uvedená v textovej podobe. A práve túto textovú podobu môžeme operátorom nameof nahradiť. Kompilátora to potom dovoľuje automaticky nahradiť názov premennej, bez toho aby sme ho museli ručne prepisovať. Prikladám ukážku použitia.

class DemoClass
{
    public int MyVariable { get; set; }

    public override string ToString()
    {
        return string.Format("Class {0} have variable named {1}",nameof(DemoClass),nameof(MyVariable));
    }
}

String Interpolation

Jedna z hlavných noviniek je nový spôsob zápisu reťazca. Tento zápis plne nahradzuje string.Format a poskytuje identickú funkcionalitu. Reťazec musí začínať znakom dolára a to ešte pred otvorením úvodzoviek. Miesto indexu dávame do zložených zátvoriek samotnú premennú, prípadne kód, z ktorého sa reťazec, ktorý sa má na zadané miesto vložiť, vypočíta. Zaujímavosťou je, že túto funkcionalitu môžeme aj vnárať, napríklad pri použití LINQ. Tieto vzorky nahrádza toString metódu v predchádzajúcom príklade a ukazuje vnorenia.

public override string ToString()
{
    return $"Class {nameof(DemoClass)} have variable named {nameof(MyVariable)}";
}

string[] World = { "Czech Republic","Europe","World"};
string Prepared=$"Hello {World.Aggregate(((working,next) => $"{working} and {next}"))}";
Console.WriteLine(Prepared); // Hello Czech Republic and Europe and World

Zachytávanie výnimiek

Použitie asynchrónnych metód v catch a finally blokoch

Tu snáď ani nie je čo vysvetľovať. Možno niekoho prekvapí, že nešlo použiť Await v catch a finally blokoch. Ja som sa s tým stretol pri programovaní aplikácií pre Windows Phone. Malo to do určitej miery svoje opodstatnenie. Pri použití asynchrónnych metód program pokračuje v kóde, ktorý na asynchrónne metódy nečaká. Ak teda máme metódu, ktorá nie je asynchrónne a ktorá volá asynchrónne metódu bez použitia Await, pri prvom výskyte Await bude program pokračovať vo volajúci metóde. Až skončí úloha, ktorá blokovala asynchrónne metódu, bude program opäť pokračovať v asynchrónne metóde, ktorá až potom skončí. V tej chvíli ale už môže byť volajúci metóda dávno hotová. Ak to prevedieme na výnimky, môže nastať situácia, keď program bude pokračovať, bez toho, aby výnimka bola plne zachytená, pretože blok catch alebo finally ešte nie je kompletný - čaká na dokončenie asynchrónne metódy. V novej verzii už je tento prípad ošetrený a môžeme použiť asynchrónne metódy aj v catch a finally blokoch. Tentoraz ukážka nebude potrebné.

Filtrovanie výnimiek

Filtrovanie výnimiek je z môjho pohľadu jedna z najzaujímavejších nových vlastností, ktoré C# 6 priniesol. Teraz sa môžeme rozhodovať o zachytenie výnimky nielen na základe jej typu, ale aj na základe vonkajšieho stavu. Syntax je nasledovná:

catch (ExceptionType e) when (expression)

kde expression môže byť ľubovoľný výraz, ktorý vracia bool. Keď hovorím ľubovoľný, skutočne myslím ľubovoľný. Môžeme sa rozhodovať na základe booleovské premenné nad try blokom, operátorov nákupný alebo aj na základe volanie metódy vracajúci bool. Teraz teda môžeme mať rôzne catch bloky pre HttpException s rôznou odpoveďou.

try {
    throw new HttpException(404,"Error");
}
catch(HttpException e) when (e.GetHttpCode() == 401) {
    Console.WriteLine("Unautorized");
}
catch(HttpException e) when (e.GetHttpCode() == 404) {
    Console.WriteLine("Not found");
}
catch(HttpException e) when (e.GetHttpCode() == 500) {
    Console.WriteLine("Internal server error");
}

Okrem filtrovania výnimiek sa dá táto funkcionalita použiť ik logovanie. Pritom nemusíme mať žiadne vnorené try bloky, nemusíme znova vyhadzovať výnimku a podobné veci, ktoré degradujú výkon aplikácie. Do podmienky dáme metódu, ktorá bude výnimku logovať, ale bude vždy vracať false - catch blok nikdy neprebehne. Nebudeme si tým narušovať zásobník, v ktorom výnimka prepadá a budeme mať presné informácie, kde sa výnimka vyskytla.

private static bool Log(Exception e)
{
    Console.WriteLine($"Loged: {e.Message}");
    return false;
}

// ... try blok

catch(Exception e) when (Log(e)) { }

Ďalšie novinky

Elvis operátor

Elvis operátor, čiže tiež oficiálne null-condition operator vznikol z ternárního operátora. Prečo zrovna názov Elvis operátor? O tom viac napovie nasledujúci obrázok.

ElvisOperator - C # - Pre pokročilých

VC # 6 sa trochu zmenil a namiesto dvojbodky používa iba bodku, práve z dôvodu, aby nebol zamenený s ternárním operátorom. Elvis operátorom môžeme nahradiť podmienku overujúce, že niečo nie je null. Ukážem starý a nový postup.

class DemoClass {
    public List<int> CustomList;
}
//….
Nullable<int> MyVariable = null;
DemoClass demo = new DemoClass();
//Old way
if (demo != null)
    if (demo.CustomList != null)
        MyVariable = demo.CustomList.Count;
//New way
MyVariable = demo?.CustomList?.Count;

Princíp je taký, že overí premennú, za ktorou stojí. Ak je null, nepokračuje ďalej s vyhodnotením a vráti null. Ak null nie je, pokračuje vo vyhodnotení tak dlho, kým nedôjde na koniec výrazu alebo kým nie je jeden z členov null. Rovnako ako v našom prípade, prvá overí, či nie je demo null, potom či nie je CustomList null a potom vráti Count. Je dôležité si uvedomiť, že Elvis operátor plne nenahrádza null podmienku. Ak chceme mať istotu, že sa konkrétna premenná nerovná null, stále budeme musieť podmienku napísať a Elvis operátor nám nepomôže.

Using static

Vedľa klasického using, ktorý importuje celý menný priestor, môžeme novo použiť aj using static, ktorý importuje iba statické metódy konkrétnej triedy. Using static importuje triedu, to ale neznamená, že môžeme vytvárať jej inštancie. K dispozícii nám budú iba statické metódy tejto triedy. Využiteľné to je napríklad pre triedu Console, ktorá sa skladá iba zo statických tried. Tu je malá ukážka.

using static System.Console;

namespace StaticUsing
{
    class Program
    {
        static void Main(string[] args)
        {
            //Vše z Console
            WriteLine("Hello World");
            int x;
            int.TryParse(ReadLine(),out x);
            Clear();
        }
    }
}

Vytváranie indexov

Niekedy potrebujeme pri vytváraní polí a slovníkov explicitne nastaviť index, pod ktorým je daná premenná k dispozícii. Napríklad pri tvorbe JSON. V minulej verzii sme museli opakovane volať metódu Add s kľúčom. Teraz je možnosť použiť indexované inicializácia priamo pri vytvorení poľa. Opäť si ukážeme ukážku, kedy prevedieme objekt na JSON.

class MyDemoClass
{
    public int X = 4;
    public int Y = 3;
    public string Text = "Hello";
    public List<string> Customlist = new List<string>()
            { "First","Second","Third" };
}
// …….
MyDemoClass Demo = new MyDemoClass();
JObject JSON = new JObject()
{
    ["X"] = Demo.X,
    ["Y"] = Demo.Y,
    ["Text"] = Demo.Text,
    ["CustomList"] = new JObject()
    {
        ["0"] = Demo.Customlist[0],
        ["1"] = Demo.Customlist[1],
        ["2"] = Demo.Customlist[2]
    }
};
Console.WriteLine(JSON);
vystup - C # - Pre pokročilých

Samozrejme sú aj efektívnejšie spôsoby, ako previesť objekt na JSON, ale pre ukážku indexácia polí to stačí. Rovnaký spôsob môžeme použiť aj pre pole, mapy, slovník a triedy im podobné. Program je oveľa prehľadnejšie a čitateľnejšie.

Tým je hlavný prehľad noviniek u konca. Pod článkom je priložený projekt, ktorý všetky novinky obsahuje a používa, je teda nutné nainštalovať Visual Studio 2015. Ako zdroj informácií mi poslúžil blog MSDN a kurz na Microsoft Virtual Academy, na ktorých nájdete ešte ďalší popis. Teraz si už len stačí novinky osvojiť a začať ich v ďalších projektoch aktívne využívať :-) .


 

Všetky články v sekcii
C # - Pre pokročilých
Článok pre vás napísal Patrik Valkovič
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
Věnuji se programování v C++ a C#. Kromě toho také programuji v PHP (Nette) a JavaScriptu (NodeJS).
Aktivity