Novinky v C#6

C# .NET Novinky v C#6

20. července 2015 se odehrálo hned několik věcí. Vyšlo nové Visual Studio 2015, dále C#6 a nakonec i .NET 4.6, který je přichystán na příchod Windows 10. My se ale zaměříme pouze na novou verzi C#.

Předtím, než přejdeme k samotnému C#, bych rád zmínil Project Roslyn. Jedná se o open-source kompiler pro Windows i Linux, určený pro C# a VB.NET. Zajímavostí je, že je napsán ve stejném jazyce, který překládá, tedy C# Roslyn kompiler je napsán v C# a přes Common Language Runtime se sám překládá Just In Time.

Nyní už k samotnému C#. Na rozdíl od předchozích verzí nepřidává nové technologie. Při pohledu do historie, C#2 přidal do jazyku možnost generického programování, C#3 lambda výrazy a poslední verze C#5 byla hodně zaměřená na asynchronní programování. Aktuální verze C#6 se zaměřuje spíše na čitelnost, udržovatelnost a správu kódu. Při pohledu na jednotlivé body se nám může zdát, že jsou nevýrazné a někdy nás dokonce překvapí, že v předchozí verzi nebyly. Tak schválně, zkoušeli jste někdy použít asynchronní metody v catch nebo finally bloku? Ve výsledku ale kód zpřehlední, často zkrátí a bude lépe udržovatelný. Teď už se pojďme podívat na jednotlivé body.

Návrh třídy

Read-only auto properties

Kolik z nás už napsalo následující část kódu, když potřebovali implementovat read-only properties?

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

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

Teoreticky bychom mohli readonly proměnnou vytvořit jako veřejnou, ale čistější je přeci jenom vytvořit ji soukromou a přistupovat k ní pomocí getteru. Například pokud bychom později název proměnné změnili, nemuseli bychom přepisovat celý program. C#6 přináší změnu, díky které můžeme definovat property pouze s auto getterm. Takové property bude muset být přiřazena hodnota přímo (nebo v konstruktoru) a není možné ji z venku změnit. Na rozdíl od druhého způsobu zápisu nelze hodnotu změnit ani v metodách třídy. Zápis vypadá následovně.

public int NewStyleReadonly { get; } = 20;

Lambda-like těla metod

Nová verze C# také přidala lamba-like těla funkcí. Opět si uvedeme původní příklad a následně i 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 kolik se zápis zkrátil a výsledek je naprosto stejný. Podmínkou tohoto zápisu je, že musí následovat pouze jeden příkaz. Jestliže se pokusíme použít složené závorky, a tedy napsat i více příkazů za sebe, kompilátor nahlásí chybu a program se nezkompiluje. To omezuje psaní dlouhých bloků kódu, které by na přehlednosti naopak ubrali.

Práce se stringem

Operátor nameof

Do nové verze se také dostal nový operátor nameof. Ten nahrazuje proměnnou jejím názvem. Využijeme to například při generování JSONu nebo u bindingu, při kterém potřebujeme mít svázanou proměnnou ve třídě s výstupem, kde je proměnná uvedena v textové podobě. A právě tuto textovou podobu můžeme operátorem nameof nahradit. Kompilátoru to poté dovoluje automaticky nahradit název proměnné, aniž bychom jej museli ručně přepisovat. Přikládám ukázku použití.

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 novinek je nový způsob zápisu řetězce. Tento zápis plně nahrazuje string.Format a poskytuje identickou funkcionalitu. Řetězec musí začínat znakem dolaru a to ještě před otevřením uvozovek. Místo indexu dáváme do složených závorek samotnou proměnnou, popřípadě kód, ze kterého se řetězec, který se má na zadané místo vložit, vypočte. Zajímavostí je, že tuto funkcionalitu můžeme i vnořovat, například při použití LINQu. Následující ukázka nahrazuje ToString metodu v předcházejícím příkladu a ukazuje vnoření.

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ávání výjimek

Použití asynchronních metod v catch a finally blocích

Zde snad ani není co vysvětlovat. Možná někoho překvapí, že nešlo použít await v catch a finally blocích. Já jsem se s tím setkal při programování aplikací pro Windows Phone. Mělo to do určité míry své opodstatnění. Při použití asynchronních metod program pokračuje v kódu, který na asynchronní metody nečeká. Máme-li tedy metodu, která není asynchronní a která volá asynchronní metodu bez použití await, při prvním výskytu await bude program pokračovat ve volající metodě. Až skončí úloha, která blokovala asynchronní metodu, bude program opět pokračovat v asynchronní metodě, která teprve poté skončí. V tu chvíli ale už může být volající metoda dávno hotová. Pokud to převedeme na výjimky, může nastat situace, kdy program bude pokračovat, aniž by výjimka byla plně zachycena, protože blok catch nebo finally ještě není kompletní - čeká na dokončení asynchronní metody. V nové verzi už je tento případ ošetřen a můžeme použít asynchronní metody i v catch a finally blocích. Tentokrát ukázka nebude potřeba.

Filtrování výjimek

Filtrování výjimek je z mého pohledu jedna z nejzajímavějších nových vlastností, které C#6 přinesl. Nyní se můžeme rozhodovat o zachycení výjimky nejenom na základě jejího typu, ale i na základě vnějšího stavu. Syntaxe je následující:

catch (ExceptionType e) when (expression)

kde expression může být libovolný výraz, který vrací bool. Když říkám libovolný, skutečně myslím libovolný. Můžeme se rozhodovat na základě booleovské proměnné nad try blokem, operátorů porovnání nebo i na základě volání metody vracející bool. Nyní tedy můžeme mít různé catch bloky pro HttpException s různou odpovědí.

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");
}

Kromě filtrování výjimek se dá tato funkcionalita použít i k logování. Přitom nemusíme mít žádné vnořené try bloky, nemusíme znovu vyhazovat výjimku a podobné věci, které degradují výkon aplikace. Do podmínky dáme metodu, která bude výjimku logovat, ale bude vždy vracet false - catch blok nikdy neproběhne. Nebudeme si tím narušovat zásobník, ve kterém výjimka propadá a budeme mít přesné informace, kde se výjimka vyskytla.

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

// ... try blok

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

Další novinky

Elvis operátor

Elvis operátor, neboli také oficiálně null-condition operator vznikl z ternárního operátoru. Proč zrovna název Elvis operátor? O tom víc napoví následující obrázek. ElvisOperator V C#6 se trochu změnil a místo dvojtečky používá pouze tečku, právě z důvodu, aby nebyl zaměněn s ternárním operátorem. Elvis operátorem můžeme nahradit podmínku ověřující, že něco není null. Ukážu 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;

Princip je takový, že ověří proměnnou, za kterou stojí. Jestliže je null, nepokračuje dále s vyhodnocením a vrátí null. Jestliže null není, pokračuje ve vyhodnocení tak dlouho, dokud nedojde na konec výrazu nebo dokud není jeden ze členů null. Stejně jako v našem případě, první ověří, zda není demo null, poté jestli není CustomList null a poté vrátí Count. Je důležité si uvědomit, že Elvis operátor plně nenahrazuje null podmínku. Pokud chceme mít jistotu, že se konkrétní proměnná nerovná null, stále budeme muset podmínku napsat a Elvis operátor nám nepomůže.

Using static

Vedle klasického using, který importuje celý jmenný prostor, můžeme nově použít i using static, který importuje pouze statické metody konkrétní třídy. Using static importuje třídu, to ale neznamená, že můžeme vytvářet její instance. K dispozici nám budou pouze statické metody této třídy. Využitelné to je například pro třídu Console, která se skládá pouze ze statických tříd. Zde je malá ukázka.

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áření indexů

Někdy potřebujeme při vytváření polí a slovníků explicitně nastavit index, pod kterým je daná proměnná k dispozici. Například při tvorbě JSONu. V minulé verzi jsme museli opakovaně volat metodu Add s klíčem. Nyní je možnost použít indexované inicializace přímo při vytvoření pole. Opět si ukážeme ukázku, kdy převedeme 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

Samozřejmě jsou i efektivnější způsoby, jak převést objekt na JSON, ale pro ukázku indexace polí to stačí. Stejný způsob můžeme použít i pro pole, mapy, slovník a třídy jim podobné. Program je mnohem přehlednější a čitelnější.

Tím je hlavní přehled novinek u konce. Pod článkem je přiložený projekt, který všechny novinky obsahuje a používá, je tedy nutné nainstalovat Visual Studio 2015. Jako zdroj informací mi posloužil blog MSDN a kurz na Microsoft Virtual Academy, na kterých najdete ještě další popis. Nyní si už jen stačí novinky osvojit a začít je v dalších projektech aktivně využívat :-).


 

Stáhnout

Staženo 17x (2.61 MB)
Aplikace je včetně zdrojových kódů v jazyce C#

 

  Aktivity (1)

Článek pro vás napsal patrik.valkovic
Avatar
Věnuji se programování v C++ a C#. Kromě toho také programuji v PHP (Nette) a JavaScriptu.

Jak se ti líbí článek?
Celkem (9 hlasů) :
55555


 


Miniatura
Předchozí článek
Visual Studio
Miniatura
Následující článek
Historie .NETu

 

 

Komentáře
Zobrazit starší komentáře (4)

Avatar
Luboš Běhounek (Satik):

zrovna Elvis mi prijde celkem uzitecnej a dost zkracujici kod v urcitych situacich :)

Odpovědět  +2 3.8.2015 15:52
:)
Avatar
Jindřich Máca
Tým ITnetwork
Avatar
Jindřich Máca:

patrik.valkovic ty chceš, abych na ten C# přešel, viď? :-D

 
Odpovědět  +1 3.8.2015 16:02
Avatar
Jan Vargovský
Redaktor
Avatar
Jan Vargovský:

Tipuju tě na nějakého javistu, který je jen jealous, protože k vám teprve nedávno došly lambdy, co? :D

 
Odpovědět  +1 3.8.2015 16:12
Avatar
patrik.valkovic
Šéfredaktor
Avatar
patrik.valkovic:

[me|]10733[/m­e|]Jindřich Máca jasně že jo :D
Jinak Elvis operátor se dá využit třeba u JSONu. Jestliže v něm mám strukturu, ze které beru data, a ta struktura tam nebude, tak nrmusím ověřovat u každé property jestli je null, ale naláduju to tam rovnou. Poslal bych ukázku, ale jsem na mobilu.
Je pravda, že se jedná o vlastnost, která se využije méně, než to na první pohled vypadá.

Odpovědět  +2 3.8.2015 16:12
Nikdy neumíme dost na to, abychom se nemohli něco nového naučit.
Avatar
Jan Vargovský
Redaktor
Avatar
Odpovídá na patrik.valkovic
Jan Vargovský:

Ono to využiješ celkem na hodně místech, jestliže máš modely, které v sobě nemají primitivní typy, ale odkazy na další classy.

 
Odpovědět 3.8.2015 16:15
Avatar
Odpovídá na Jan Vargovský
Neaktivní uživatel:

Nie som javista ani nič podobné, je to len môj názor, pretože niektoré tie veci síce skracujú kód, ale zhoršujú jeho čítateľnosť.

Odpovědět  ±0 3.8.2015 16:18
Neaktivní uživatelský účet
Avatar
Jan Vargovský
Redaktor
Avatar
Odpovídá na patrik.valkovic
Jan Vargovský:

Btw, máš tam chybu v kódu u readonly propert.

Neaktivní uživatel Jasne no, to už je věc názoru :)

 
Odpovědět 3.8.2015 16:21
Avatar
Odpovídá na Neaktivní uživatel
Michal Žůrek (misaz):

otázka zní jestli jsou čitelnější tři otazníky než tři zanořené podmínky. Určitě to může začátečníky překvapit to beze sporu, ale čitelnost to podle mě může naopak leda zvýšit.

Nicméně se jedná o další "bezejmennou" vlastnost jazyka, takže je dobré zvážit v nějakých komplikovanějších situacích využití komentáře.

Odpovědět 5.8.2015 22:54
Nesnáším {}, proto se jim vyhýbám.
Avatar
Tomáš "CrashTest" Bitter:

"Elvis operátor plně nenahrazuje null podmínku."

Důležitá otázka: Kdy se dá elvis spolehlivě použít ?

Odpovědět 5.8.2015 23:31
Need for Steve
Avatar
Tomáš "CrashTest" Bitter:

A když už jsme u syntactic sugar, tak by nebylo od věci zavést reverzní foreach, páč už mě nebaví promazávat kolekci přes for ...

Odpovědět 9.8.2015 22:26
Need for Steve
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 14. Zobrazit vše