Co nowego w języku C# 12

Język C# 12 zawiera następujące nowe funkcje. Możesz wypróbować te funkcje przy użyciu najnowszej wersji programu Visual Studio 2022 lub zestawu .NET 8 SDK.

  • Konstruktory podstawowe — wprowadzono w programie Visual Studio 2022 w wersji 17.6 (wersja zapoznawcza 2).

  • Wyrażenia kolekcji — wprowadzone w programie Visual Studio 2022 w wersji 17.7 (wersja zapoznawcza 5).

  • Tablice wbudowane — wprowadzono w programie Visual Studio 2022 w wersji 17.7 (wersja zapoznawcza 3).

  • Parametry opcjonalne w wyrażeniach lambda — wprowadzono w programie Visual Studio 2022 w wersji 17.5 (wersja zapoznawcza 2).

  • ref readonly parameters — wprowadzono w programie Visual Studio 2022 w wersji 17.8 (wersja zapoznawcza 2).

  • Alias dowolnego typu — wprowadzono w programie Visual Studio 2022 w wersji 17.6 (wersja zapoznawcza 3).

  • Atrybut eksperymentalny — wprowadzony w programie Visual Studio 2022 w wersji 17.7 (wersja zapoznawcza 3).

  • Funkcja przechwytywania - w wersji zapoznawczej wprowadzona w programie Visual Studio 2022 w wersji 17.7 (wersja zapoznawcza 3).

Język C# 12 jest obsługiwany na platformie .NET 8. Aby uzyskać więcej informacji, zobacz Przechowywanie wersji języka C#.

Najnowszą wersję zestawu .NET 8 SDK można pobrać ze strony pobierania platformy .NET. Możesz również pobrać program Visual Studio 2022, który zawiera zestaw SDK platformy .NET 8.

Uwaga

Interesuje nas Twoja opinia na temat tych funkcji. Jeśli znajdziesz problemy z dowolną z tych nowych funkcji, utwórz nowy problem w repozytorium dotnet/roslyn .

Konstruktory podstawowe

Teraz można tworzyć konstruktory podstawowe w dowolnym class obiekcie i struct. Konstruktory podstawowe nie są już ograniczone do record typów. Podstawowe parametry konstruktora są w zakresie całej treści klasy. Aby upewnić się, że wszystkie podstawowe parametry konstruktora są zdecydowanie przypisane, wszystkie jawnie zadeklarowane konstruktory muszą wywołać konstruktor podstawowy przy użyciu this() składni. Dodanie konstruktora podstawowego do elementu class uniemożliwia kompilatorowi deklarowanie niejawnego konstruktora bez parametrów. W obiekcie structniejawny konstruktor bez parametrów inicjuje wszystkie pola, w tym podstawowe parametry konstruktora do wzorca 0-bitowego.

Kompilator generuje właściwości publiczne tylko dla podstawowych parametrów konstruktora w record typach record class lub record struct typach. Nierekordowe klasy i struktury mogą nie zawsze chcieć tego zachowania dla podstawowych parametrów konstruktora.

Więcej informacji na temat konstruktorów podstawowych można dowiedzieć się w samouczku dotyczącym eksplorowania konstruktorów podstawowych i artykułu na temat konstruktorów wystąpień.

Wyrażenia kolekcji

Wyrażenia kolekcji wprowadzają nową składnię terse w celu utworzenia typowych wartości kolekcji. Inlining other collections into these values is possible using a spread operator ...

Można utworzyć kilka typów podobnych do kolekcji bez konieczności obsługi zewnętrznej listy BCL. Są to następujące typy:

W poniższych przykładach pokazano użycie wyrażeń kolekcji:

// Create an array:
int[] a = [1, 2, 3, 4, 5, 6, 7, 8];

// Create a list:
List<string> b = ["one", "two", "three"];

// Create a span
Span<char> c  = ['a', 'b', 'c', 'd', 'e', 'f', 'h', 'i'];

// Create a jagged 2D array:
int[][] twoD = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];

// Create a jagged 2D array from variables:
int[] row0 = [1, 2, 3];
int[] row1 = [4, 5, 6];
int[] row2 = [7, 8, 9];
int[][] twoDFromVariables = [row0, row1, row2];

Operator.. spreadu w wyrażeniu kolekcji zastępuje argument elementami z tej kolekcji. Argument musi być typem kolekcji. W poniższych przykładach pokazano, jak działa operator spreadu:

int[] row0 = [1, 2, 3];
int[] row1 = [4, 5, 6];
int[] row2 = [7, 8, 9];
int[] single = [.. row0, .. row1, .. row2];
foreach (var element in single)
{
    Console.Write($"{element}, ");
}
// output:
// 1, 2, 3, 4, 5, 6, 7, 8, 9,

Operand operatora spread jest wyrażeniem, które można wyliczyć. Operator spread ocenia każdy element wyrażenia wyliczenia.

Możesz używać wyrażeń kolekcji w dowolnym miejscu, w którym potrzebujesz kolekcji elementów. Mogą określić początkową wartość kolekcji lub przekazać jako argumenty do metod, które przyjmują typy kolekcji. Więcej informacji na temat wyrażeń kolekcji można znaleźć w artykule dotyczącym wyrażeń kolekcji lub specyfikacji funkcji.

ref readonly Parametry

Język C# dodał in parametry jako sposób przekazywania odwołań do odczytu. in parametry zezwalają zarówno na zmienne, jak i wartości, i mogą być używane bez adnotacji argumentów.

Dodanie parametrów ref readonly zapewnia większą przejrzystość interfejsów API, które mogą używać ref parametrów lub in parametrów:

  • Interfejsy API utworzone przed in wprowadzeniem mogą być używane ref , mimo że argument nie jest modyfikowany. Te interfejsy API można zaktualizować za pomocą polecenia ref readonly. Nie będzie to zmiana powodująca niezgodność dla wywołań, tak jak gdyby ref parametr został zmieniony na in. Może to być na przykład System.Runtime.InteropServices.Marshal.QueryInterface.
  • Interfejsy API, które przyjmują in parametr, ale logicznie wymagają zmiennej. Wyrażenie wartości nie działa. Może to być na przykład System.ReadOnlySpan<T>.ReadOnlySpan<T>(T).
  • Interfejsy API, które używają ref , ponieważ wymagają zmiennej, ale nie zmutuj tej zmiennej. Może to być na przykład System.Runtime.CompilerServices.Unsafe.IsNullRef.

Aby dowiedzieć się więcej o ref readonly parametrach, zobacz artykuł dotyczący modyfikatorów parametrów w dokumentacji językowej lub specyfikacji funkcji parametrów readonly ref.

Domyślne parametry lambda

Teraz można zdefiniować wartości domyślne dla parametrów w wyrażeniach lambda. Składnia i reguły są takie same jak dodawanie wartości domyślnych argumentów do dowolnej metody lub funkcji lokalnej.

Więcej informacji na temat parametrów domyślnych w wyrażeniach lambda można znaleźć w artykule dotyczącym wyrażeń lambda.

Alias dowolnego typu

Możesz użyć using dyrektywy aliasu do aliasu dowolnego typu, a nie tylko nazwanych typów. Oznacza to, że można tworzyć aliasy semantyczne dla typów krotki, typów tablic, typów wskaźników lub innych niebezpiecznych typów. Aby uzyskać więcej informacji, zobacz specyfikację funkcji.

Tablice wbudowane

Tablice wbudowane są używane przez zespół środowiska uruchomieniowego i innych autorów bibliotek w celu zwiększenia wydajności aplikacji. Tablice wbudowane umożliwiają deweloperowi utworzenie tablicy o stałym rozmiarze w typie struct . Struktura z wbudowanym buforem powinna zapewniać charakterystykę wydajności podobną do niebezpiecznego bufora o stałym rozmiarze. Prawdopodobnie nie zadeklarujesz własnych tablic wbudowanych, ale używasz ich w sposób niewidoczny, gdy są one widoczne jako System.Span<T> lub System.ReadOnlySpan<T> obiekty z interfejsów API środowiska uruchomieniowego.

Tablica śródliniowa jest zadeklarowana podobnie do następującejstruct:

[System.Runtime.CompilerServices.InlineArray(10)]
public struct Buffer
{
    private int _element0;
}

Są one używane jak każda inna tablica:

var buffer = new Buffer();
for (int i = 0; i < 10; i++)
{
    buffer[i] = i;
}

foreach (var i in buffer)
{
    Console.WriteLine(i);
}

Różnica polega na tym, że kompilator może korzystać ze znanych informacji o tablicy wbudowanej. Prawdopodobnie używasz tablic wbudowanych, tak jak każda inna tablica. Aby uzyskać więcej informacji na temat deklarowania tablic wbudowanych, zobacz dokumentację języka dla struct typów.

Atrybut eksperymentalny

Typy, metody lub zestawy można oznaczyć za System.Diagnostics.CodeAnalysis.ExperimentalAttribute pomocą elementu , aby wskazać funkcję eksperymentalną. Kompilator wyświetla ostrzeżenie, jeśli uzyskujesz dostęp do metody lub wpisz adnotację za pomocą elementu ExperimentalAttribute. Wszystkie typy zawarte w zestawie oznaczonym atrybutem Experimental są eksperymentalne. Więcej informacji można znaleźć w artykule Dotyczącym atrybutów ogólnych odczytanych przez kompilator lub specyfikację funkcji.

Interceptory

Ostrzeżenie

Przechwytywanie to funkcja eksperymentalna dostępna w trybie zapoznawczym w języku C# 12. Ta funkcja może ulec zmianie powodującej niezgodność lub usunięciu w przyszłej wersji. W związku z tym nie jest zalecane w przypadku aplikacji produkcyjnych ani wydanych.

Aby można było używać przechwytywania, projekt użytkownika musi określić właściwość <InterceptorsPreviewNamespaces>. Jest to lista przestrzeni nazw, które mogą zawierać przechwytniki.

Na przykład: <InterceptorsPreviewNamespaces>$(InterceptorsPreviewNamespaces);Microsoft.AspNetCore.Http.Generated;MyLibrary.Generated</InterceptorsPreviewNamespaces>.

Przechwytator to metoda, która deklaratywnie zastępuje wywołanie metody przechwytowalnej wywołaniem samego siebie w czasie kompilacji. To podstawienie występuje poprzez zadeklarowanie lokalizacji źródłowych wywołań przechwyconych przez przechwytywanie. Przechwytniki zapewniają ograniczoną możliwość zmiany semantyki istniejącego kodu przez dodanie nowego kodu do kompilacji, na przykład w generatorze źródłowym.

Przechwytywanie jest używane jako część generatora źródłowego do modyfikowania zamiast dodawania kodu do istniejącej kompilacji źródłowej. Generator źródła zastępuje wywołania metody przechwytowalnej wywołaniem metody przechwytywania.

Jeśli interesuje Cię eksperymentowanie z przechwytownikami, możesz dowiedzieć się więcej, czytając specyfikację funkcji. Jeśli używasz tej funkcji, pamiętaj, aby zachować aktualną każdą zmianę specyfikacji funkcji dla tej funkcji eksperymentalnej. Jeśli funkcja zostanie sfinalizowana, dodamy więcej wskazówek dotyczących tej witryny.

Zobacz też