Artykuły | 21 wrzesień, 2022

C# 11 – sprawdź, co nowego!

Co roku pojawia się nowa wersja języka programowania C#. Wersja C# 11 ujrzy światło dzienne w listopadzie 2022 roku wraz z .NET 7. W tym artykule przyjrzę się wybranym ważnym funkcjonalnościom C# 11. Czekasz na tę aktualizację i zastanawiasz się, co nowego się pojawi? Zapoznaj się z moim miniprzewodnikiem i sprawdź, czy nowe funkcje są warte uwagi i w jaki sposób mogą usprawnić pracę programistów.

C# 11 – sprawdź, co nowego!

Historia C#

  • Styczeń 2002 – C# 1.0
  • Listopad 2005 – C# 2.0
  • Listopad 2007 – C# 3.0 (.NET Framework 3.0 i 3.5)
  • Listopad 2007 – C# 4.0
  • Sierpień 2012 – C# 5.0
  • Lipiec 2015 – C# 6.0
  • Marzec 2017 – C# 7.0 (.NET Framework 4.0)
  • Wrzesień 2019 – C# 8.0
  • Listopad 2020 – C# 9.0 (.NET Framework 5)
  • Listopad 2021 – C# 10.0
nearshore 2023.03.xx graphic 1 68

Najbliższa aktualizacja – funkcje C# udostępnione w wersji zapoznawczej

Wydaje się, że nie tak dawno witaliśmy .NET 6 i C# 10, a już niebawem, w listopadzie 2022 roku, pojawi się kolejna aktualizacja. Jesteś ciekaw, jakie nowe funkcje przyniesie najnowsza wersja C#? Każdy programista może przekonać się sam za pomocą Visual Studio 2022 w wersji 17.3 (niektóre z nowych funkcji są dostępne we wcześniejszych wersjach VS – np. Visual Studio 17.1). Nowości można również zobaczyć w aplikacji .NET 7 SDK w wersji zapoznawczej (do pobrania na platformę .NET).

nearshore 2023.03.xx graphic 2 69

  Visual Studio 2022 – features for preview

  17.3

  17.2

  17.1

Source: Microsoft

Poniżej znajdziesz przegląd, moim zdaniem, najciekawszych z nich.

Generic attributes

Wersja C# 11 została wyposażona w funkcjonalność generic attributes. Pozwala ona utworzyć klasę ogólną wywodzącą się z klasy System.Attribute, która ułatwia tworzenie atrybutów wymagających parametru System.Type. We wcześniejszych wersjach C# programista musiał tworzyć bardziej złożone rozwiązania w zakresie atrybutów z parametrem Type w konstruktorze. Przykład:

public class TypeAttribute : Attribute
{
public TypeAttribute (Type t) => ParamType = t;

public Type ParamType {get; }
}
[TypeAttribute(typeof(string))]
public  string Method () => default;

W przypadku C# 11 można to osiągnąć w prostszy sposób:

public class GenericAttribute : Attribute { }
[GenericAttribute ()]
public string Method () => default;

Usunięcie obowiązkowego użycia typeof(…) w atrybutach i zastąpienie go typami rodzajowymi eliminuje problem związany z zapewnieniem, że typ wewnątrz typeof() będzie spełniać wymogi atrybutów. Ta funkcja miała się ukazać we wcześniejszych wersjach C#, ale ze względu na niezgodność z narzędziami deweloperskimi Microsoft zdecydował się przełożyć datę jej premiery. Teraz jednak nadszedł jej czas!

Generic math support

Pod tą nazwą kryje się kilka nowych funkcji, które razem składają się na generic math support. Są to:

  • static virtual oraz static abstract members in interfaces
  • checked user defined operators
  • relaxed shift operators
  • unsigned right-shift operator

Ta funkcja pozwala programistom używać statycznych interfejsów API z kodu ogólnego. Pozwala np. w jednej implementacji wdrożyć kalkulator sumy lub średniej dla różnych typów liczb. Więcej szczegółów na temat nowej składni znajdziesz w dokumentacji C#. Typy numeryczne implementują nowy interfejs INumber, który zawiera właściwości T.One i T.Zero. Można to wykorzystać do implementacji kalkulatorów sumy ogólnej lub średniej dla wielu typów liczb, zachowując zasadę DRY. Metoda ta może być również zaimplementowana jako operator +.

Można go znaleźć w następującym listingu:

T Sum< T >(T[] values) where T : INumber<T>
{
T result = T.Zero;
foreach (var value in values)
   {
 result += value;
   }
return result;
}
 
T Sum< T >(T[] values) where T : INumber<T>
{
var sum = Sum(values);
var count = T.Zero;
for (var i = 0; i < values.Length; i++)
   {
count += T.One;
   }
return sum / count;
}
var  ints = new [] {1, 2, 3, 4, 5};
var  doubles = new [] { 0.1, 0.7, 1.1, 8.3 };
 
var  sumOfInts = Sum(ints);
var  avgOfInts = Avg(ints);
var  sumOfDoubles = Sum(doubles);
var  avgOfDoubles = Avg(doubles);

Funkcja generic math support wpłynęła na inne aspekty w C# 11:

  • operator right-shift – za pomocą operatora > > > można wymusić dowolne przesunięcia w prawo do nieprzypisanych operatorów right-shift, co oznacza, że pozycje pustych bitów wysokiego rzędu są zawsze ustawione na zero, niezależnie od typu argumentu po lewej stronie.
  • relaxed shift operator – począwszy od wersji C# 11, drugi argument miany nie musi być argumentem int lub domyślnie konwertowalnym do int, co pozwala na użycie tego operatora w ogólnych interfejsach matematycznych
  • zaznaczone (i niezaznaczone) zdefiniowane operatory – można zdefiniować arytmetyczne operatory. Kompilator generuje wywołania do właściwego wariantu w oparciu o bieżący kontekst

Nowe linie w interpolacjach ciągów znaków

Ta funkcja po raz pierwszy pojawiła się w C# 6 wraz z Visual Studio 2015. Zastępuje ona String.Format(). Format interpolacji ciągów znaków jest ciągiem wewnątrz cudzysłowów podwójnych, poprzedzonych $. Wewnątrz tego ciągu można określić parametry lub wykonanie metody w nawiasach {}.

$"{<interpolationExpression>[,<alignment>][:<formatString>]} other text in string”

Wraz z C# 11 funkcja zyskuje niewielką aktualizację, która pozwoli zawierać nowe linie wewnątrz formuł. Wcześniej niektóre długie formuły zawierające zapytania LINQ mogły być nieczytelne. Już tak nie będzie. Wraz z kolejnym wydaniem C# będziemy mogli używać nowych linii, a tym samym – skomplikowane formuły będą wyglądać o niebo lepiej.

var  list = new [] {"Apple", "Banana", "Orange", "Grapefruit"};
var  str = $"Third letters of fruits starts with B: {list
   .Gdzie(fruit => fruit.StartsWith("B"))
   .Select(fruit => fruit[2])
   .FirstOrDefault()} ";

List patterns

Dopasowanie wzorca – dopasowanie obiektu do typu w przypadku instrukcji wielokrotnego wyboru, ale nie tylko. Więcej informacji na temat dopasowywania wzorców można znaleźć w dokumentacji Microsoft. Dopasowanie wzorca zostało wprowadzone w C# 7 ze słowem kluczowym is pozwalającym zmapować obiekt do typu i when – słowem kluczowym do użycia w instrukcjach wielokrotnego wyboru.

Następnie C# 7.1 rozwinął wzorce typów do obsługi typów ogólnych. C# 8 ulepszył dopasowywanie wzorców, dodając wzorce właściwości pozwalające dobrać typ i właściwość. Kolejne wydanie C# przyniosło wzorce relacyjne. Zatem od wersji C# 9 możemy użyć >, <, >=, <= w dopasowywaniu właściwości. C# 9 umożliwił użycie operatorów logicznych and, or, not, is null, is not null w dopasowaniu wzorca i var – słowa kluczowego do tworzenia zmiennych. C# 10 rozszerzył jeszcze wzorce własności… a teraz kolej na możliwości, jakie oferuje C# 11.

Wzorce listy – dopasowanie sekwencji elementów. Listę można dopasować, używając niektórych elementów jako wzorca. Discard pattern (_) służy do dopasowania dowolnych pojedynczych elementów, a wzorzec zakresu (..) – do dopasowania dowolnej sekwencji zerowych lub większej liczby elementów.

var  list = new [] {
new [] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10},// A
new [] {1, 2, 3, 5, 7, 10},// B
new [] {0, 2, 3, 8, 10, 10},// C
new [] {3, 4, 10},// D
nowe [] {1, 4, 10, 15, 21, 3, 10},// E
nowe [] {-1, 2, 3, 5, -1, 10}// F
};

•	Match complete list:
 list.Where(x => x is [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);// matches list A
•	Match some elements:
 list.Where(x => x is [_, 2, 3,_,_, 10]);// matches lists B, C, F
•	Match range:
 list.Where(x => x is [1, 2, .., 10]);// matches lists A, B
•	Mixed match for elements and range:
 list.Where(x => x is [1,_, .., 10]);// matches lists A, B, E
•	Match list starting with negative number:
 list.Where(x => x is [< 0, ..]);// matches list F

Raw string literals

Nieprzetworzone literały ciągów mogą być wielowierszowe, zawierać cudzysłowy i inne znaki specjalne bez sekwencji ucieczki (escape) oraz interpolacje ciągów. Oto kilka przykładów:

var  line2 = "line2 from another variable";
 
var  str1 = ""
line1
{line2} - won't be replaced
line3
line4 
       
line6
"";
 
var  str2 = $""
line1 from second string
{line2}
line3
"";
 
var  str3 = $$""
using { in line 1}
{{line2}}
{line2} this won't be replaced
{{{line2}}} you can use it like this
"" ;

Required members

Developerzy zyskują możliwość oznaczania właściwości i pól z użyciem modyfikatora required. Pozwala to upewnić się, że dane wartości są inicjowane w konstruktorze. Następnie należy ustawić atrybut SetsRequiredMembers na konstruktor, który powinien zainicjować wartości. Możesz mieć konstruktory bez atrybutu, nie muszą inicjować one wymaganych wartości.

Wymagane elementy muszą być zainicjowane, ale można je zainicjować do wartości null. W przypadku typu referencyjnego niedopuszczającego wartości null kompilator wysyła ostrzeżenie, jeśli zainicjujesz element do tej wartości. Jeśli element (member) nie jest w ogóle zainicjowany, kompilator wystawia błąd.

Parametr null-checking – odłożony po wersji zapoznawczej

W C# 11 planowano dodać funkcję sprawdzania parametru null, ale została ona na razie odłożona ze względu na zastrzeżenia developerów na Spotkaniu C# Language Design, które odbyło się 6 kwietnia 2022 r. Funkcja została udostępniona do wglądu i szeroko omówiona. Podczas gdy wielu developerów było zadowolonych, inni mieli wszelkiego rodzaju zastrzeżenia.

Auto-default struct

Przed wydaniem C# 11 programiści musieli tworzyć konstruktory strukturalne o parametrach zapewniających inicjowanie wszystkich pól. C# 11 sprawi, że będzie inaczej. Na razie można utworzyć strukturę z konstruktorem bez parametrów, który nie inicjuje od razu elementów struktury. Następnie zadaniem kompilatora jest sprawić, by wszystkie jeszcze niezainicjowane pola zostały zainicjowane do ich wartości domyślnej. Kompilator dodaje niezbędny kod na początku body konstruktora, przed uzyskaniem dostępu do pól. Jeśli jest to możliwe przed zainicjowaniem wszystkich pól, struktura zostanie zainicjowana do wartości domyślnej przed wykonaniem korpusu konstruktora.

Więcej o inicjowaniu struktury i wartościach domyślnych w C# można przeczytać na stronie dokumentacji Microsoft.

public  readonly struct AutoDefaultStruct
{
public int IntegerValue {get; }
public string StringValue {get; }
public double DoubleValue {get; }

public AutoDefaultStruct ()
    {
//IntegerValue = default;
//StringValue = default;
//DoubleValue = default;
// nie musi ustawiać wartości dla wszystkich pól, domyślne inicjalizacje zostaną dodane na początku konstruktora przez kompilator
    }
}

var structDemo = new AutoDefaultStruct(); 

Podsumowanie: programisto, przygotuj się na więcej funkcji C# 11!

Powyżej opisałem najważniejsze funkcje C# 11, które można nawet dziś sprawdzić w wersji zapoznawczej. Pełna lista zmian jest rzecz jasna znacznie dłuższa i obejmuje:

  • Rozszerzony zakres nameof
  • Dopasowanie wzorca dla Span<char> i ReadOnlySpan<char>
  • Aliasy dla IntPtr i UIntPtr

Oraz wiele więcej! Dokumentację techniczną możesz znaleźć w serwisie GitHub.

Przeczytaj także te artykuły:
Extreme Programming
Mikroserwisy – nowy standard?

Mateusz jest absolwentem informatyki na Politechnice Poznańskiej. Głównie zajmuje się programowaniem w C#, w ostatnich latach programista rozwiązań webowych wchodzący w świat frontendu w Angularze. Prywatnie szczęśliwy mąż i ojciec wspaniałej córeczki, czekający aż maleństwo podrośnie, aby móc wyruszyć na wspólne, rodzinne wycieczki motocyklowe.

Zapisz się do newslettera, ekskluzywna zawartość czeka

Bądź na bieżąco z najnowszymi artykułami i wydarzeniami IT

Informacje dotyczące przetwarzania danych osobowych

Zapisz się do newslettera, ekskluzywna zawartość czeka

Bądź na bieżąco z najnowszymi artykułami i wydarzeniami IT

Informacje dotyczące przetwarzania danych osobowych

Zapisz się do newslettera, aby pobrać plik

Bądź na bieżąco z najnowszymi artykułami i wydarzeniami IT

Informacje dotyczące przetwarzania danych osobowych

Dziękujemy za zapis na newsletter — został ostatni krok do aktywacji

Potwierdź poprawność adresu e-mail klikając link wiadomości, która została do Ciebie wysłana w tej chwili.

 

Jeśli w czasie do 5 minut w Twojej skrzynce odbiorczej nie będzie wiadomości to sprawdź również folder *spam*.

Twój adres e-mail znajduje się już na liście odbiorców newslettera

Wystąpił nieoczekiwany błąd

Spróbuj ponownie za chwilę.

    Get notified about new articles

    Be a part of something more than just newsletter

    I hereby agree that Inetum Polska Sp. z o.o. shall process my personal data (hereinafter ‘personal data’), such as: my full name, e-mail address, telephone number and Skype ID/name for commercial purposes.

    I hereby agree that Inetum Polska Sp. z o.o. shall process my personal data (hereinafter ‘personal data’), such as: my full name, e-mail address and telephone number for marketing purposes.

    Read more

    Just one click away!

    We've sent you an email containing a confirmation link. Please open your inbox and finalize your subscription there to receive your e-book copy.

    Note: If you don't see that email in your inbox shortly, check your spam folder.