Menu Górne
C# 8.0

C# 8.0 zbliża się wielkimi krokami. Choć oficjalna premiera została zapowiedziana wraz z .Net Core 3.0 (który ma zostać oddany do końca 2019 roku) to już teraz bez problemu możemy skorzystać z jego wersji zapoznawczej. Tym razem dobrodziejstw jest podobno sporo, więc postanowiłem to sprawdzić. Zapraszam do lektury.

Wymagania

Aby użyć języka C# w wersji ósmej potrzebujemy .Net Core 3.0 lub dowolnej innej platformy implementującej .Net standard 2.1. Jak wiemy .Net Core jest aktualnie w wersji preview, więc abyśmy mogli go użyć w systemie Windows potrzebujemy Visual Studio 2019 oraz .Net Core 3.0. Jeżeli (tak jak ja) używacie Visual Studio for mac to na teraz trzeba przełączyć aktualizacje na kanał preview. Dodatkowo potrzebujemy oczywiście .Net Core 3.0. Po instalacji powyższych w projekcie powinniśmy wybrać Target Framework (.Net Core 3.0) oraz wersję języka (8).

.Net Core

Ciekawsze zmiany w C# 8.0

Nullowalne typy referencyjne

Możemy je włączyć dla całego projektu lub w kodzie poprzez dyrektywę: „#nullable enable” (w wersji ostatecznej gdy C# 8.0 będzie już oficjalnie dostępny funkcja ta będzie włączana domyślnie). Zmiana ta ma na celu zablokowania możliwości przypisania nulla do typów referencyjnych jak np. string. Spowoduje to, że kod:

string st = null;

Wygeneruje ostrzeżenie przez kompilator:

C# 8.0

Aby temu zapobiec powinniśmy jawnie zadeklarować że typ ma być nullowalny.

string? st = null;

Kompilator stosując analizę przepływu sprawdza czy typy referencyjne zostały zainicjowane wartością inną niż null podczas deklaracji. W ten sposób kompilator zwróci nam uwagę miedzy innymi na: nieprzypisanie wartości w konstruktorze, deklarację zmiennej bez inicjalizacji, a gdy np. określimy jawnie typ nullowalny (przez dodanie”?”) ostrzeże nas przed użyciem zmiennej potencjalnie bez wartości. To bardzo prosty przykład ale myślę że dość dobrze obrazuje nadchodzące zmiany.

Nowy switch

To według mnie najciekawsza zmiana w nowej wersji języka. Choć z technicznego punktu widzenia to „syntax sugar”, to według mnie potrzebny i bardzo wygodny. Żeby pokazać zalety nowego switcha przejdziemy płynnie od „starej wersji”. Pisząc stara wersja mam na myśli c# >7.0 oraz zakładam że funkcje z siódmej wersji takie jak Pattern Matching są Ci znane. Na początek załóżmy sobie taki obiekt:

        public class Employee
        {
            public string FirstName { get; set; }
            public string? SecondName { get; set; }
            public string Surname { get; set; }
            public EmploymentState State { get; set; }
            public bool InWorkNow { get; set; }
        }

Jak widzisz użyłem w nim już nowej składni z #nullable aby przy okazji pokazać je w akcji. Efekt jest taki, że kompilator ostrzega że FirstName oraz Surname jest niezainicjalizowany:

C# 8.0
#nullable enable w akcji

Wróćmy jednak do switcha. Obiecana stara wersja switcha w c# >7.0 wykorzystując pattern matching:

switch (employee)
            {
                case Employee emp when emp.State == EmploymentState.employed && emp.InWorkNow:
                    Console.WriteLine($"Pracownik {employee.FirstName} {employee.Surname} jest w pracy.");
                    break;
                case Employee emp when emp.State == EmploymentState.employed && !emp.InWorkNow:
                    Console.WriteLine($"Pracownik {employee.FirstName} {employee.Surname} jest zatrudniony ale nieobecny.");
                    break;
                case Employee emp when emp.State == EmploymentState.fired && emp.InWorkNow:
                    Console.WriteLine($"Pracownik {employee.FirstName} {employee.Surname} jest nielegalnie w pracy.");
                    break;
                case Employee emp when emp.State == EmploymentState.fired && !emp.InWorkNow:
                    Console.WriteLine($"Pracownik {employee.FirstName} {employee.Surname} został zwolniony i jest nieobeny.");
                    break;
                default:
                    throw new InvalidOperationException();
            }

W nowej wersji języka twórcy pozbyli się właściwie wszystkiego co niepotrzebne i powtarzające się. Aż chciałoby się krzyknąć: nareszcie! bo przecież ile można klepać tych break’ów i case’ów… 🙂 W ten oto sposób powyższy kod możemy przekształcić w dużo prostszy i moim zdaniem czytelniejszy:

string result = employee switch
            {
                Employee { State: EmploymentState.employed, InWorkNow: true } emp => "jest w pracy.",
                Employee { State: EmploymentState.employed, InWorkNow: false } emp => "jest zatrudniony ale nieobecny.",
                Employee { State: EmploymentState.fired, InWorkNow: true } emp => "jest nielegalnie w pracy.",
                Employee { State: EmploymentState.fired, InWorkNow: false } emp => "został zwolniony i jest nieobeny.",
                _ => throw new InvalidOperationException()
            };
            Console.WriteLine($"Pracownik { employee.FirstName} { employee.Surname} {result}");

Ale co tu się właściwie stało? Przede wszystkim zmieniła się składnia na tę dobrze znaną w .Net czyli wyrażenia lambda. Dodatkowo dostaliśmy nowy mechanizm który nazywa się „Property Pattern” i umożliwia pominięcie when w warunkach. Efekt działania switcha jest identyczny jak w poprzedniej wersji. Dodatkowo tutaj zwracamy wynik switch’a bezpośrednio do zmiennej co pozwala nam wyodrębnić cześć powtarzanego kodu do osobnej lini, fajnie prawda? Ale to jeszcze nie koniec :). Tuples to nie nowość z C# w wersji ósmej ale wykorzystanie ich w bloku switch już tak. Dzięki temu możemy jeszcze „podkolorować” ten kod:

string result = (employee.State, employee.InWorkNow) switch
            {
                (EmploymentState.employed, true) => "jest w pracy.",
                (EmploymentState.employed, false) => "jest zatrudniony ale nieobecny.",
                (EmploymentState.fired, true) => "jest nielegalnie w pracy.",
                (EmploymentState.fired, false) => "został zwolniony i jest nieobeny.",
                _ => throw new InvalidOperationException()
            };
            Console.WriteLine($"Pracownik { employee.FirstName} { employee.Surname} {result}");

Co powiesz na to? Jest różnica prawda? Teraz zobacz pierwszą wersję kodu i ostatnią. Porównaj i daj znać co o tym myślisz?

Podzakresy

Nie wiem czy właściwie nazwałem ten akapit ale chciałbym w nim napisać kilka słów o bardzo prostej ale wydaje mi się przydatnej funkcji jaką są podzakresy. Podzakres to nic innego jak ograniczony zbiór wybrany z kolekcji. Możemy w nim określić początkowy i końcowy indeks z zakresu źródłowego. Przypomina wam to coś? Bo dla mnie jest to dość podobne do substringa. Subrange ma jednak jedną dodatkową zaletę: możemy określać indeksy od końca! Robimy to dodając znak ^ przed numerem indeksu. Samo określanie indeksów wygląda w następujący sposób:

var words = new string[]
{
                // index from start    index from end
    "The",      // 0                   ^9
    "quick",    // 1                   ^8
    "brown",    // 2                   ^7
    "fox",      // 3                   ^6
    "jumped",   // 4                   ^5
    "over",     // 5                   ^4
    "the",      // 6                   ^3
    "lazy",     // 7                   ^2
    "dog"       // 8                   ^1
};              // 9 (or words.Length) ^0

A więc w powyższym, kod:

var lazyDog = words[^3..^0];

zwróci nam : „the”, „lazy”, „dog”. Proste, prawda?

Podsumowanie

Zmiany w nowej wersji nie są fundamentalne z technicznego punktu widzenia, jednak patrząc na to przez pryzmat użytkowania są bardzo sensowne i potrzebne. Szczególnie nowa składnia w poleceniu switch bardzo mi się spodobała. Oczywiście to co opisałem jest tylko ułamek tego co czeka nas wraz z nadejściem C# w wersji ósmej. Jeżeli jednak zainteresował Cię mój wpis to odsyłam do źródeł które znajdują się na końcu artykułu. Kod używany w tym artykule również jest dostępny na GitHubie bloga.

źródła:
Kod aplikacji na GitHub
Nullable MS docs tutorial
What’s new in c# 8 MS docs
Mads Torgersen C# 8 (youtube)

O autorze

Niepoprawny optymista. 100 pomysłów na sekundę, wielbiciel nowych technologii, nie tylko z rodziny .Net. Często nosi przy sobie jabłko, takie nadgryzione... ;)

3 Comments

  1. C# 8.0 – developer.net.pl

    Dziękujemy za dodanie artykułu – Trackback z dotnetomaniak.pl

  2. Dla mnie małym bohaterem nowej wersji C# są jak to nazwałeś „podzakresy”. Niby prosta rzecz, ale dostępna już w tak wielu językach programowania, że aż prosiło się by w końcu znalazła się również w C#.
    Ale nie powiem, ten nowy switch z pattern matchingiem rodem z języków funkcyjnych też wydaje się być ekstra!

    • Ja najbardziej jaram się switchem 🙂 Pattern matching, tuples w switch jest dla mnie extra. A tak zupełnie poza tematem c# 8.0 u mnie bardzo użyteczne stały się tuples.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *

Możesz używać znaczników języka HTML i ich atrybutów: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Zamknij