Co nowego C# 8.0What's new in C# 8.0

Istnieje wiele ulepszeń C# języka, które możesz wypróbować już.There are many enhancements to the C# language that you can try out already.

Uwaga

W tym artykule został ostatnio zaktualizowany na potrzeby C# 8.0 w wersji zapoznawczej 5.This article was last updated for C# 8.0 preview 5.

Te funkcje można krótko opisano w dalszej części tego artykułu.The remainder of this article briefly describes these features. Jeżeli dostępne są szczegółowe artykuły, znajdują się linki do omówienia i samouczki.Where in-depth articles are available, links to those tutorials and overviews are provided.

Elementy członkowskie tylko do odczytuReadonly members

Można zastosować readonly modyfikator do wszystkich elementów członkowskich struktury.You can apply the readonly modifier to any member of a struct. Oznacza to element członkowski nie powoduje modyfikacji stanu.It indicates that the member does not modify state. Jest bardziej szczegółowe niż stosowanie readonly modyfikatora struct deklaracji.It's more granular than applying the readonly modifier to a struct declaration. Należy rozważyć następujące struktury mutable:Consider the following mutable struct:

public struct Point
{
    public double X { get; set; }
    public double Y { get; set; }
    public double Distance => Math.Sqrt(X * X + Y * Y);

    public override string ToString() =>
        $"({X}, {Y}) is {Distance} from the origin";
}

Większość struktur, takich jak ToString() metoda nie powoduje modyfikacji stanu.Like most structs, the ToString() method does not modify state. Może sygnalizować, dodając readonly modyfikatora deklaracji ToString():You could indicate that by adding the readonly modifier to the declaration of ToString():

public readonly override string ToString() =>
    $"({X}, {Y}) is {Distance} from the origin";

Zmian poprzednim generuje ostrzeżenie kompilatora, ponieważ ToString uzyskuje dostęp do Distance właściwość, która nie jest oznaczony jako readonly:The preceding change generates a compiler warning, because ToString accesses the Distance property, which is not marked readonly:

warning CS8656: Call to non-readonly member 'Point.Distance.get' from a 'readonly' member results in an implicit copy of 'this'

Kompilator ostrzega o tym, kiedy zachodzi potrzeba utworzenia kopii obrony.The compiler warns you when it needs to create a defensive copy. Distance Właściwości nie zmienia stanu, dzięki czemu możesz rozwiązać tego ostrzeżenia, dodając readonly modyfikatora deklaracji:The Distance property does not change state, so you can fix this warning by adding the readonly modifier to the declaration:

public readonly double Distance => Math.Sqrt(X * X + Y * Y);

Należy zauważyć, że readonly modyfikator jest konieczne na właściwością tylko do odczytu.Notice that the readonly modifier is necessary on a read only property. Kompilator nie zakłada get akcesory nie należy modyfikować stanu; należy zadeklarować readonly jawnie.The compiler doesn't assume get accessors do not modify state; you must declare readonly explicitly. Kompilator wymusić regułę, która readonly elementów członkowskich, nie należy modyfikować stanu.The compiler does enforce the rule that readonly members do not modify state. Poniższa metoda nie zostanie skompilowany, chyba że usuniesz readonly modyfikator:The following method will not compile unless you remove the readonly modifier:

public readonly void Translate(int xOffset, int yOffset)
{
    X += xOffset;
    Y += yOffset;
}

Ta funkcja umożliwia określanie zgodną z planem projektu, dzięki czemu kompilator może go wymusić i wprowadzić optymalizacje oparte na tym przeznaczeniem.This feature lets you specify your design intent so the compiler can enforce it, and make optimizations based on that intent.

Domyślni członkowie interfejsuDefault interface members

Można teraz dodawać członków do interfejsów i zapewniać implementację dla tych członków.You can now add members to interfaces and provide an implementation for those members. Tej funkcji języka umożliwia autorom interfejsu API Dodaj metody do interfejsu w nowszych wersjach bez przerywania źródła lub zgodność binarną przy użyciu istniejących implementacji interfejsu.This language feature enables API authors to add methods to an interface in later versions without breaking source or binary compatibility with existing implementations of that interface. Istniejących implementacji dziedziczą domyślną implementację.Existing implementations inherit the default implementation. Ta funkcja umożliwia również C# pod kątem współdziałania z interfejsów API przeznaczonych dla systemu Android lub Swift, który obsługuje podobne funkcje.This feature also enables C# to interoperate with APIs that target Android or Swift, which support similar features. Domyślne elementy członkowskie z interfejsu też włączyć scenariusze podobne do funkcji języka "cech".Default interface members also enable scenarios similar to a "traits" language feature.

Domyślni członkowie interfejsu wpływa na wiele scenariuszy i elementy języka.Default interface members affects many scenarios and language elements. Nasz pierwszy samouczek obejmuje aktualizowanie interfejs za pomocą domyślnej implementacji.Our first tutorial covers updating an interface with default implementations. Inne samouczki i dokumentacja aktualizacje zostaną wprowadzone w termin głównym wydaniu.Other tutorials and reference updates are coming in time for general release.

Więcej wzorców w większej liczbie miejscMore patterns in more places

Dopasowanie wzorca udostępnia narzędzia do zapewnienia funkcji zależnych od kształtu powiązane, ale różnych typów danych.Pattern matching gives tools to provide shape-dependent functionality across related but different kinds of data. C#Składnia dla typów deseni i wzory stałych 7.0 wprowadza się przy użyciu is wyrażenia i switch instrukcji.C# 7.0 introduced syntax for type patterns and constant patterns by using the is expression and the switch statement. Te funkcje reprezentowane pierwszych kroków niepewnego kierunku obsługi paradygmatów programowania, w których funkcji i danych na żywo od siebie.These features represented the first tentative steps toward supporting programming paradigms where data and functionality live apart. Przemieszcza się w branży więcej mikrousług i innymi architektury oparte na chmurze, potrzebne są inne narzędzia języka.As the industry moves toward more microservices and other cloud-based architectures, other language tools are needed.

C#8.0 rozwija tego słownika, aby można było używać więcej wzorzec wyrażenia w wielu miejscach w kodzie.C# 8.0 expands this vocabulary so you can use more pattern expressions in more places in your code. Gdy Twoje dane i funkcje są oddzielone, należy wziąć pod uwagę te funkcje.Consider these features when your data and functionality are separate. Należy wziąć pod uwagę w przypadku algorytmów zależą od faktów, innej niż typ środowiska uruchomieniowego obiektu dopasowywania do wzorca.Consider pattern matching when your algorithms depend on a fact other than the runtime type of an object. Metody te zawierają express projekty w inny sposób.These techniques provide another way to express designs.

Oprócz nowych wzorców w nowych miejscach C# dodaje 8.0 wzorców cyklicznego.In addition to new patterns in new places, C# 8.0 adds recursive patterns. Wynik dowolne wyrażenie wzorca jest wyrażeniem.The result of any pattern expression is an expression. Wzorzec cyklicznego jest po prostu wyrażenie wzorzec, które są stosowane do danych wyjściowych innego wyrażenia wzorca.A recursive pattern is simply a pattern expression applied to the output of another pattern expression.

Wyrażenia Switchswitch expressions

Często switch instrukcja generuje wartości w każdym z jego case bloków.Often, a switch statement produces a value in each of its case blocks. Przełącz wyrażenia umożliwiają korzystanie z bardziej zwięzłym składni wyrażeń.Switch expressions enable you to use more concise expression syntax. Istnieją mniej powtarzalne case i break słów kluczowych i mniej nawiasów klamrowych.There are fewer repetitive case and break keywords, and fewer curly braces. Na przykład należy wziąć pod uwagę następujące wyliczenia, który wyświetla kolory tęczowego:As an example, consider the following enum that lists the colors of the rainbow:

public enum Rainbow
{
    Red,
    Orange,
    Yellow,
    Green,
    Blue,
    Indigo,
    Violet
}

Jeśli definicja aplikacji RGBColor typu, który jest konstruowany z R, G i B składników, można przekonwertować Rainbow wartość do jego wartości RGB, przy użyciu następującej metody zawierającą wyrażenie switch:If your application defined an RGBColor type that is constructed from the R, G and B components, you could convert a Rainbow value to its RGB values using the following method containing a switch expression:

public static RGBColor FromRainbow(Rainbow colorBand) =>
    colorBand switch
    {
        Rainbow.Red    => new RGBColor(0xFF, 0x00, 0x00),
        Rainbow.Orange => new RGBColor(0xFF, 0x7F, 0x00),
        Rainbow.Yellow => new RGBColor(0xFF, 0xFF, 0x00),
        Rainbow.Green  => new RGBColor(0x00, 0xFF, 0x00),
        Rainbow.Blue   => new RGBColor(0x00, 0x00, 0xFF),
        Rainbow.Indigo => new RGBColor(0x4B, 0x00, 0x82),
        Rainbow.Violet => new RGBColor(0x94, 0x00, 0xD3),
        _              => throw new ArgumentException(message: "invalid enum value", paramName: nameof(colorBand)),
    };

Istnieje kilka ulepszeń składni tutaj:There are several syntax improvements here:

  • Zmienna znajduje się przed switch — słowo kluczowe.The variable comes before the switch keyword. Inną kolejność ułatwia wizualnie do odróżnienia wyrażenia switch z instrukcji switch.The different order makes it visually easy to distinguish the switch expression from the switch statement.
  • case i : elementy są zastępowane =>.The case and : elements are replaced with =>. Jest bardziej zwięzłe i intuicyjne.It's more concise and intuitive.
  • default Przypadek jest zastępowany _ odrzucić.The default case is replaced with a _ discard.
  • Jednostki są wyrażeniami, nie instrukcji.The bodies are expressions, not statements.

Natomiast, za pomocą klasycznego kodu równoważne switch instrukcji:Contrast that with the equivalent code using the classic switch statement:

public static RGBColor FromRainbowClassic(Rainbow colorBand)
{
    switch (colorBand)
    {
        case Rainbow.Red:
            return new RGBColor(0xFF, 0x00, 0x00);
        case Rainbow.Orange:
            return new RGBColor(0xFF, 0x7F, 0x00);
        case Rainbow.Yellow:
            return new RGBColor(0xFF, 0xFF, 0x00);
        case Rainbow.Green:
            return new RGBColor(0x00, 0xFF, 0x00);
        case Rainbow.Blue:
            return new RGBColor(0x00, 0x00, 0xFF);
        case Rainbow.Indigo:
            return new RGBColor(0x4B, 0x00, 0x82);
        case Rainbow.Violet:
            return new RGBColor(0x94, 0x00, 0xD3);
        default:
            throw new ArgumentException(message: "invalid enum value", paramName: nameof(colorBand));
    };
}

Wzorce właściwościProperty patterns

Wzorzec właściwość pozwala do dopasowania właściwości obiektu badania.The property pattern enables you to match on properties of the object examined. Należy wziąć pod uwagę witryny handlu elektronicznego, który należy obliczyć podatku od sprzedaży, w oparciu o adres kupującego.Consider an eCommerce site that must compute sales tax based on the buyer's address. Obliczenie jest nie odpowiedzialność za rdzeń Address klasy.That computation is not a core responsibility of an Address class. Zostanie on zmieniony wraz z upływem czasu, prawdopodobnie częściej niż zmiany formatu adresu.It will change over time, likely more often than address format changes. Kwota podatku od sprzedaży, który jest zależny od State właściwości adresu.The amount of sales tax depends on the State property of the address. Poniższa metoda używa wzorca właściwości można obliczyć podatku od sprzedaży, adres i ceny:The following method uses the property pattern to compute the sales tax from the address and the price:

public static decimal ComputeSalesTax(Address location, decimal salePrice) =>
    location switch
    {
        { State: "WA" } => salePrice * 0.06M,
        { State: "MN" } => salePrice * 0.75M,
        { State: "MI" } => salePrice * 0.05M,
        // other cases removed for brevity...
        _ => 0M
    };

Dopasowanie wzorca tworzy zwarta składnia dla wyrażania ten algorytm.Pattern matching creates a concise syntax for expressing this algorithm.

Wzorce krotkiTuple patterns

Niektóre algorytmy są zależne od wielu danych wejściowych.Some algorithms depend on multiple inputs. Wzorce krotki zezwala na przełączanie na podstawie wielu wartości wyrażonej w postaci krotki.Tuple patterns allow you to switch based on multiple values expressed as a tuple. Poniższy kod pokazuje wyrażenie switch dla gry rock, dokument, nożyczek:The following code shows a switch expression for the game rock, paper, scissors:

public static string RockPaperScissors(string first, string second)
    => (first, second) switch
    {
        ("rock", "paper") => "rock is covered by paper. Paper wins.",
        ("rock", "scissors") => "rock breaks scissors. Rock wins.",
        ("paper", "rock") => "paper covers rock. Paper wins.",
        ("paper", "scissors") => "paper is cut by scissors. Scissors wins.",
        ("scissors", "rock") => "scissors is broken by rock. Rock wins.",
        ("scissors", "paper") => "scissors cuts paper. Scissors wins.",
        (_, _) => "tie"
    };

Komunikaty wskazują zwycięzca.The messages indicate the winner. W przypadku odrzucenia reprezentuje trzy kombinacje w celach węzłów lub inne dane wejściowe tekstu.The discard case represents the three combinations for ties, or other text inputs.

Wzorce pozycyjnePositional patterns

Niektóre typy obejmują Deconstruct metodę, która deconstructs jego właściwości w zmiennych dyskretnego.Some types include a Deconstruct method that deconstructs its properties into discrete variables. Gdy Deconstruct metody jest dostępny, można użyć pozycyjne wzorców sprawdzić właściwości obiektu i korzystać z tych właściwości dla wzorca.When a Deconstruct method is accessible, you can use positional patterns to inspect properties of the object and use those properties for a pattern. Należy wziąć pod uwagę następujące Point klasy, która obejmuje Deconstruct metodę, aby utworzyć zmienne dyskretnego X i Y:Consider the following Point class that includes a Deconstruct method to create discrete variables for X and Y:

public class Point
{
    public int X { get; }
    public int Y { get; }

    public Point(int x, int y) => (X, Y) = (x, y);

    public void Deconstruct(out int x, out int y) =>
        (x, y) = (X, Y);
}

Ponadto należy wziąć pod uwagę następujące wyliczenia, który reprezentuje różne stanowiska quadrant:Additionally, consider the following enum that represents various positions of a quadrant:

public enum Quadrant
{
    Unknown,
    Origin,
    One,
    Two,
    Three,
    Four,
    OnBorder
}

Używa następującej metody pozycyjne wzorzec do wyodrębnienia wartości x i y.The following method uses the positional pattern to extract the values of x and y. Następnie używa when klauzuli, aby określić Quadrant punktu:Then, it uses a when clause to determine the Quadrant of the point:

static Quadrant GetQuadrant(Point point) => point switch
{
    (0, 0) => Quadrant.Origin,
    var (x, y) when x > 0 && y > 0 => Quadrant.One,
    var (x, y) when x < 0 && y > 0 => Quadrant.Two,
    var (x, y) when x < 0 && y < 0 => Quadrant.Three,
    var (x, y) when x > 0 && y < 0 => Quadrant.Four,
    var (_, _) => Quadrant.OnBorder,
    _ => Quadrant.Unknown
};

Podczas pasuje do wzorca odrzucania w poprzednim przełącznika albo x lub y jest 0, ale nie oba.The discard pattern in the preceding switch matches when either x or y is 0, but not both. Wyrażenie switch musi mieć wartość albo zgłosić wyjątek.A switch expression must either produce a value or throw an exception. Wyrażenie switch zgłasza wyjątek, jeśli żaden z przypadków są zgodne.If none of the cases match, the switch expression throws an exception. Kompilator generuje ostrzeżenia dla Ciebie, jeśli nie obejmują wszystkich możliwych przypadków w wyrażeniu przełącznika.The compiler generates a warning for you if you do not cover all possible cases in your switch expression.

Możesz zapoznać się z technik, w tym dopasowania do wzorca zaawansowane samouczek na temat dopasowywania do wzorca.You can explore pattern matching techniques in this advanced tutorial on pattern matching.

Za pomocą deklaracjiusing declarations

A użycie — deklaracja jest deklaracja zmiennej jest poprzedzony using — słowo kluczowe.A using declaration is a variable declaration preceded by the using keyword. Go informuje kompilator, że na końcu zasięgu powinny zostać zlikwidowane deklarowanej zmiennej.It tells the compiler that the variable being declared should be disposed at the end of the enclosing scope. Na przykład rozważmy następujący kod, który zapisuje plik tekstowy:For example, consider the following code that writes a text file:

static void WriteLinesToFile(IEnumerable<string> lines)
{
    using var file = new System.IO.StreamWriter("WriteLines2.txt");
    foreach (string line in lines)
    {
        // If the line doesn't contain the word 'Second', write the line to the file.
        if (!line.Contains("Second"))
        {
            file.WriteLine(line);
        }
    }
// file is disposed here
}

W powyższym przykładzie plik jest usuwany po osiągnięciu zamykającego nawiasu klamrowego dla metody.In the preceding example, the file is disposed when the closing brace for the method is reached. To już koniec zakresu, w którym file jest zadeklarowana.That's the end of the scope in which file is declared. Powyższy kod jest równoważny z następującym kodem przy użyciu klasycznej za pomocą instrukcji instrukcji:The preceding code is equivalent to the following code using the classic using statements statement:

static void WriteLinesToFile(IEnumerable<string> lines)
{
    using (var file = new System.IO.StreamWriter("WriteLines2.txt"))
    {
        foreach (string line in lines)
        {
            // If the line doesn't contain the word 'Second', write the line to the file.
            if (!line.Contains("Second"))
            {
                file.WriteLine(line);
            }
        }
    } // file is disposed here
}

W powyższym przykładzie plik zostanie usunięty skojarzony zamykającego nawiasu klamrowego using osiągnięta zostanie instrukcja.In the preceding example, the file is disposed when the closing brace associated with the using statement is reached.

W obu przypadkach, kompilator generuje wywołanie Dispose().In both cases, the compiler generates the call to Dispose(). Kompilator generuje błąd, jeśli wyrażenie za pomocą instrukcji nie jest możliwe do likwidacji.The compiler generates an error if the expression in the using statement is not disposable.

Statyczne funkcje lokalneStatic local functions

Teraz możesz dodać static modyfikatora funkcje lokalne, aby upewnić się, że funkcja lokalna nie przechwytuje (odwołanie w) wszystkie zmienne z otaczającego zakresu.You can now add the static modifier to local functions to ensure that local function doesn't capture (reference) any variables from the enclosing scope. Ten sposób generuje CS8421, "statycznych funkcji lokalnej nie może zawierać odwołanie do <zmienna >."Doing so generates CS8421, "A static local function can't contain a reference to <variable>."

Rozważmy poniższy kod.Consider the following code. Funkcja lokalna LocalFunction uzyskuje dostęp do zmiennej y, zadeklarowana w otaczającym zakresie (metoda M).The local function LocalFunction accesses the variable y, declared in the enclosing scope (the method M). W związku z tym LocalFunction nie może być zadeklarowana z static modyfikator:Therefore, LocalFunction can't be declared with the static modifier:

int M()
{
    int y;
    LocalFunction();
    return y;

    void LocalFunction() => y = 0;
}

Poniższy kod zawiera funkcję statyczną lokalnego.The following code contains a static local function. Może być statyczne, ponieważ system nie ma dostępu do żadnych zmiennych w obejmującym zakresie:It can be static because it doesn't access any variables in the enclosing scope:

int M()
{
    int y = 5;
    int x = 7;
    return Add(x, y);

    static int Add(int left, int right) => left + right;
}

Struktury ref możliwe do rozporządzaniaDisposable ref structs

A struct zadeklarowane za pomocą ref modyfikator nie może implementować żadnych interfejsów i dlatego nie może implementować IDisposable.A struct declared with the ref modifier may not implement any interfaces and so cannot implement IDisposable. W związku z tym aby umożliwić ref struct usuwana, musi mieć dostępne void Dispose() metody.Therefore, to enable a ref struct to be disposed, it must have an accessible void Dispose() method. Dotyczy to również readonly ref struct deklaracji.This also applies to readonly ref struct declarations.

Typy referencyjne dopuszczające wartość nullNullable reference types

W kontekście annotation dopuszczający wartość null, dowolnej zmiennej typu odwołania jest uważany za Typ referencyjny niedopuszczające wartości null.Inside a nullable annotation context, any variable of a reference type is considered to be a nonnullable reference type. Jeśli chcesz wskazać, że zmienna może mieć wartości null, należy dołączyć nazwę typu z ? Aby zadeklarować zmienną jako typu dopuszczającego wartość null odwołania.If you want to indicate that a variable may be null, you must append the type name with the ? to declare the variable as a nullable reference type.

Dla typów odwołań kolumną kompilator używa analizę przepływu, aby upewnić się, że zmienne lokalne są inicjowane na wartość inną niż null, gdy zadeklarowana.For nonnullable reference types, the compiler uses flow analysis to ensure that local variables are initialized to a non-null value when declared. Pola muszą być zainicjowane w trakcie konstruowania.Fields must be initialized during construction. Kompilator generuje ostrzeżenie, jeśli zmienna nie jest ustawiony przez wywołanie do dowolnych dostępnych konstruktorów lub inicjatora.The compiler generates a warning if the variable is not set by a call to any of the available constructors or by an initializer. Ponadto typy odwołań kolumną nie można przypisać wartość, która może mieć wartości null.Furthermore, nonnullable reference types can't be assigned a value that could be null.

Typy dopuszczające wartości null odwołań nie są sprawdzany w celu zapewnienia ich nie są przypisywany lub zainicjowany do wartości null.Nullable reference types aren't checked to ensure they aren't assigned or initialized to null. Jednak kompilator używa analizę przepływu, aby upewnić się, że jakakolwiek zmienna typu odwołania dopuszczającego wartość null jest sprawdzana względem o wartości null, przed jego dostępny lub przypisane do typu odwołania niedopuszczające wartości null.However, the compiler uses flow analysis to ensure that any variable of a nullable reference type is checked against null before it's accessed or assigned to a nonnullable reference type.

Dowiedz się więcej na temat funkcji w przeglądzie typy dopuszczające wartości null odwołań.You can learn more about the feature in the overview of nullable reference types. Samodzielnie wypróbować tę funkcję w nowej aplikacji, w tym samouczek typy dopuszczające wartości null odwołanie.Try it yourself in a new application in this nullable reference types tutorial. Dowiedz się więcej o kroki, aby migrować dane istniejącej bazy kodu w zapewnienie użytkowania typy dopuszczające wartości null odwołań w migrowania aplikacji do użycia odwołania nullable typy samouczek.Learn about the steps to migrate an existing codebase to make use of nullable reference types in the migrating an application to use nullable reference types tutorial.

Asynchroniczne strumienieAsynchronous streams

Począwszy od C# 8.0, możesz utworzyć i wykorzystują strumienie asynchronicznie.Starting with C# 8.0, you can create and consume streams asynchronously. Metody, która zwraca strumień asynchroniczny ma trzy właściwości:A method that returns an asynchronous stream has three properties:

  1. Jest zadeklarowana za pomocą async modyfikator.It's declared with the async modifier.
  2. Zwraca IAsyncEnumerable<T>.It returns an IAsyncEnumerable<T>.
  3. Metoda zawiera yield return instrukcji, aby zwrócić kolejne elementy w strumieniu asynchronicznym.The method contains yield return statements to return successive elements in the asynchronous stream.

Korzystanie z strumień asynchroniczny wymaga dodania await — słowo kluczowe przed foreach — słowo kluczowe podczas wyliczania elementów strumienia.Consuming an asynchronous stream requires you to add the await keyword before the foreach keyword when you enumerate the elements of the stream. Dodawanie await — słowo kluczowe wymaga metody, która wylicza strumień asynchroniczny, które mają zostać zadeklarowane za pomocą async modyfikator i zwracać typ, jest dozwolony dla async metody.Adding the await keyword requires the method that enumerates the asynchronous stream to be declared with the async modifier and to return a type allowed for an async method. Zwykle oznacza to, zwracając Task lub Task<TResult>.Typically that means returning a Task or Task<TResult>. Może to być także ValueTask lub ValueTask<TResult>.It can also be a ValueTask or ValueTask<TResult>. Metoda może wykorzystywać i generuje strumień asynchroniczny, oznacza to, co spowoduje przywrócenie IAsyncEnumerable<T>.A method can both consume and produce an asynchronous stream, which means it would return an IAsyncEnumerable<T>. Poniższy kod generuje sekwencji z zakresu od 0 do 19 oczekiwania 100 ms między generowania poszczególnych liczb:The following code generates a sequence from 0 to 19, waiting 100 ms between generating each number:

public static async System.Collections.Generic.IAsyncEnumerable<int> GenerateSequence()
{
    for (int i = 0; i < 20; i++)
    {
        await Task.Delay(100);
        yield return i;
    }
}

Należy wyliczyć, przy użyciu sekwencji await foreach instrukcji:You would enumerate the sequence using the await foreach statement:

await foreach (var number in GenerateSequence())
{
    Console.WriteLine(number);
}

Możesz spróbować asynchronicznymi strumieniami samodzielnie w naszym samouczku tworzenia i używania strumieni asynchronicznych.You can try asynchronous streams yourself in our tutorial on creating and consuming async streams.

Indeksy i zakresyIndices and ranges

Zakresy i indeksów, które zapewniają zwięzłą składnię do określania podzakresów w tablicy, Span<T>, lub ReadOnlySpan<T>.Ranges and indices provide a succinct syntax for specifying subranges in an array, Span<T>, or ReadOnlySpan<T>.

Obsługa tego języka opiera się na dwóch nowych typów i dwóch nowych operatorów.This language support relies on two new types, and two new operators.

  • System.Index reprezentuje indeks do sekwencji.System.Index represents an index into a sequence.
  • ^ Operatora, który określa, że indeks względem końca sekwencji.The ^ operator, which specifies that an index is relative to the end of the sequence.
  • System.Range reprezentuje zakres sub sekwencji.System.Range represents a sub range of a sequence.
  • Operator zakresu (..), który określa początek i koniec zakresu, co jest operandów.The Range operator (..), which specifies the start and end of a range as is operands.

Zacznijmy od reguł dla indeksów.Let's start with the rules for indexes. Należy wziąć pod uwagę tablicy sequence.Consider an array sequence. 0 Indeksu jest taka sama jak sequence[0].The 0 index is the same as sequence[0]. ^0 Indeksu jest taka sama jak sequence[sequence.Length].The ^0 index is the same as sequence[sequence.Length]. Należy pamiętać, że sequence[^0] zgłosić wyjątek, podobnie jak sequence[sequence.Length] jest.Note that sequence[^0] does throw an exception, just as sequence[sequence.Length] does. Dowolną liczbą n, indeks ^n jest taka sama jak sequence.Length - n.For any number n, the index ^n is the same as sequence.Length - n.

Określa zakres start i zakończenia zakresu.A range specifies the start and end of a range. Początek zakresu (włącznie), ale koniec zakresu jest wzajemnie, co oznacza start znajduje się w zakresie, ale zakończenia nie wchodzi w zakres.The start of the range is inclusive, but the end of the range is exclusive, meaning the start is included in the range but the end is not included in the range. Zakres [0..^0] reprezentuje cały zakres, podobnie jak [0..sequence.Length] reprezentuje cały zakres.The range [0..^0] represents the entire range, just as [0..sequence.Length] represents the entire range.

Spójrzmy na kilka przykładów.Let's look at a few examples. Rozważmy następującą tablicę, oznaczony za pomocą jej indeks, od samego początku i na końcu:Consider the following array, annotated with its index from the start and from the end:

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

Możesz pobrać ostatni wyraz z ^1 indeksu:You can retrieve the last word with the ^1 index:

Console.WriteLine($"The last word is {words[^1]}");
// writes "dog"

Poniższy kod tworzy Podzakres przy użyciu słowa "szybkie", "brown" i "fox".The following code creates a subrange with the words "quick", "brown", and "fox". Zawiera on words[1] za pośrednictwem words[3].It includes words[1] through words[3]. Element words[4] nie znajduje się w zakresie.The element words[4] is not in the range.

var quickBrownFox = words[1..4];

Poniższy kod tworzy Podzakres "z opóźnieniem" i "dog".The following code creates a subrange with "lazy" and "dog". Zawiera on words[^2] i words[^1].It includes words[^2] and words[^1]. Indeks końcowy words[^0] nie jest dołączony:The end index words[^0] is not included:

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

Poniższe przykłady tworzą zakresy, które są otwarte zakończył się dla początkowego i końcowego:The following examples create ranges that are open ended for the start, end, or both:

var allWords = words[..]; // contains "The" through "dog".
var firstPhrase = words[..4]; // contains "The" through "fox"
var lastPhrase = words[6..]; // contains "the, "lazy" and "dog"

Zakresy można również zadeklarować jako zmienne:You can also declare ranges as variables:

Range phrase = 1..4;

Zakres następnie można używać wewnątrz [ i ] znaków:The range can then be used inside the [ and ] characters:

var text = words[phrase];

Możesz zapoznać się więcej na temat indeksów i zakresów adresów w tym samouczku na indeksów i zakresy.You can explore more about indices and ranges in the tutorial on indices and ranges.