Przejdź do:
- 1. Historia C#
- 2. Najbliższa aktualizacja – funkcje C# udostępnione w wersji zapoznawczej
- 3. Generic attributes
- 4. Generic math support
- 5. Nowe linie w interpolacjach ciągów znaków
- 6. List patterns
- 7. Raw string literals
- 8. Required members
- 9. Parametr null-checking
- 10. Auto-default struct
- 11. Podsumowanie
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
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).
Visual Studio 2022 – features for preview
17.3
- Generic math supportauto-default structs
- Pattern match Span<char> on a constant string
- Extended nameof scope
- Numeric IntPtr
- UTF-8 string literals
- Required members
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?
Przejdź do:
- 1. Historia C#
- 2. Najbliższa aktualizacja – funkcje C# udostępnione w wersji zapoznawczej
- 3. Generic attributes
- 4. Generic math support
- 5. Nowe linie w interpolacjach ciągów znaków
- 6. List patterns
- 7. Raw string literals
- 8. Required members
- 9. Parametr null-checking
- 10. Auto-default struct
- 11. Podsumowanie