Udostępnij za pośrednictwem


Dopasowywanie wzorca — is wyrażenia i switch oraz operatory and, ori not we wzorcach

is Używasz wyrażenia, instrukcji switch i wyrażenia switch, aby dopasować wyrażenie wejściowe do dowolnej liczby cech. Język C# obsługuje wiele wzorców, w tym deklarację, typ, stałą, relacyjną, właściwość, listę, var i odrzucanie. Wzorce można łączyć przy użyciu słów kluczowych logiki logicznej and, ori not.

Następujące wyrażenia i instrukcje języka C# obsługują dopasowywanie wzorców:

W tych konstrukcjach można dopasować wyrażenie wejściowe do dowolnego z następujących wzorców:

  • Wzorzec deklaracji: aby sprawdzić typ czasu wykonywania wyrażenia i, jeśli dopasowanie powiedzie się, przypisz wynik wyrażenia do zadeklarowanej zmiennej.
  • Wzorzec typu: aby sprawdzić typ czasu wykonywania wyrażenia.
  • Wzorzec stałej: aby przetestować, czy wynik wyrażenia jest równy określonej stałej.
  • Wzorce relacyjne: aby porównać wynik wyrażenia z określoną stałą.
  • Wzorce logiczne: aby przetestować, czy wyrażenie pasuje do logicznej kombinacji wzorców.
  • Wzorzec właściwości: aby przetestować, czy właściwości lub pola wyrażenia pasują do zagnieżdżonych wzorców.
  • Wzorzec pozycyjny: aby zdekonstruować wynik wyrażenia i sprawdzić, czy wynikowe wartości pasują do zagnieżdżonych wzorców.
  • var wzorzec: aby dopasować dowolne wyrażenie i przypisać jego wynik do zadeklarowanej zmiennej.
  • Odrzuć wzorzec: aby dopasować dowolne wyrażenie.
  • Wzorce list: aby przetestować, czy sekwencja elementów pasuje do odpowiednich wzorców zagnieżdżonych. Wprowadzono w języku C# 11.

Wzorce logiczne, właściwości, pozycyjne i list to wzorce cykliczne. Oznacza to, że mogą zawierać zagnieżdżone wzorce.

Aby zapoznać się z przykładem używania tych wzorców do tworzenia algorytmu opartego na danych, zobacz Samouczek: używanie dopasowywania wzorców do tworzenia algorytmów opartych na typach i opartych na danych.

Wzorce deklaracji i typów

Używasz deklaracji i wzorców typów, aby sprawdzić, czy typ czasu wykonywania wyrażenia jest zgodny z danym typem. Za pomocą wzorca deklaracji można również zadeklarować nową zmienną lokalną. Gdy wzorzec deklaracji pasuje do wyrażenia, ta zmienna ma przypisany wynik przekonwertowanego wyrażenia, jak pokazano w poniższym przykładzie:

object greeting = "Hello, World!";
if (greeting is string message)
{
    Console.WriteLine(message.ToLower());  // output: hello, world!
}

Wzorzec deklaracji z typem T jest zgodny z wyrażeniem, gdy wynik wyrażenia ma wartość inną niż null, a każdy z następujących warunków jest spełniony:

  • Typ czasu wykonywania wyniku wyrażenia to T.

  • Typ czasu wykonywania wyniku wyrażenia pochodzi z typu T, implementuje interfejs Tlub inną niejawną konwersję odwołania istnieje z niego do T. W poniższym przykładzie pokazano dwa przypadki, gdy ten warunek ma wartość true:

    var numbers = new int[] { 10, 20, 30 };
    Console.WriteLine(GetSourceLabel(numbers));  // output: 1
    
    var letters = new List<char> { 'a', 'b', 'c', 'd' };
    Console.WriteLine(GetSourceLabel(letters));  // output: 2
    
    static int GetSourceLabel<T>(IEnumerable<T> source) => source switch
    {
        Array array => 1,
        ICollection<T> collection => 2,
        _ => 3,
    };
    

    W poprzednim przykładzie przy pierwszym wywołaniu metody pierwszy wzorzec pasuje do GetSourceLabel wartości argumentu, ponieważ typ int[] czasu wykonywania argumentu Array pochodzi z typu . W drugim wywołaniu GetSourceLabel metody typ List<T> czasu wykonywania argumentu nie pochodzi z Array typu, ale implementuje ICollection<T> interfejs.

  • Typ czasu wykonywania wyniku wyrażenia jest typem wartości dopuszczanej do wartości null z typem bazowym T.

  • Konwersja boksu lub rozpasania istnieje z typu czasu wykonywania wyniku wyrażenia na typ T.

W poniższym przykładzie przedstawiono dwa ostatnie warunki:

int? xNullable = 7;
int y = 23;
object yBoxed = y;
if (xNullable is int a && yBoxed is int b)
{
    Console.WriteLine(a + b);  // output: 30
}

Jeśli chcesz sprawdzić tylko typ wyrażenia, możesz użyć odrzucenia _ zamiast nazwy zmiennej, jak pokazano w poniższym przykładzie:

public abstract class Vehicle {}
public class Car : Vehicle {}
public class Truck : Vehicle {}

public static class TollCalculator
{
    public static decimal CalculateToll(this Vehicle vehicle) => vehicle switch
    {
        Car _ => 2.00m,
        Truck _ => 7.50m,
        null => throw new ArgumentNullException(nameof(vehicle)),
        _ => throw new ArgumentException("Unknown type of a vehicle", nameof(vehicle)),
    };
}

W tym celu można użyć wzorca typu, jak pokazano w poniższym przykładzie:

public static decimal CalculateToll(this Vehicle vehicle) => vehicle switch
{
    Car => 2.00m,
    Truck => 7.50m,
    null => throw new ArgumentNullException(nameof(vehicle)),
    _ => throw new ArgumentException("Unknown type of a vehicle", nameof(vehicle)),
};

Podobnie jak wzorzec deklaracji, wzorzec typu pasuje do wyrażenia, gdy wynik wyrażenia jest inny niż null, a jego typ czasu wykonywania spełnia dowolne z powyższych warunków.

Aby sprawdzić, czy nie ma wartości null, możesz użyć negowanegonull stałej, jak pokazano w poniższym przykładzie:

if (input is not null)
{
    // ...
}

Aby uzyskać więcej informacji, zobacz sekcje Wzorzec deklaracji i Wzorzec typu notatek propozycji funkcji.

Wzorzec stałej

Wzorzec stałej służy do testowania, czy wynik wyrażenia jest równy określonej stałej, jak pokazano w poniższym przykładzie:

public static decimal GetGroupTicketPrice(int visitorCount) => visitorCount switch
{
    1 => 12.0m,
    2 => 20.0m,
    3 => 27.0m,
    4 => 32.0m,
    0 => 0.0m,
    _ => throw new ArgumentException($"Not supported number of visitors: {visitorCount}", nameof(visitorCount)),
};

W wzorcu stałym można użyć dowolnego wyrażenia stałego, takiego jak:

Wyrażenie musi być typem, który jest konwertowany na typ stały, z jednym wyjątkiem: wyrażenie, którego typ jest Span<char> lub ReadOnlySpan<char> może być dopasowane do ciągów stałych w języku C# 11 i nowszych wersjach.

Użyj wzorca stałej, aby sprawdzić , nulljak pokazano w poniższym przykładzie:

if (input is null)
{
    return;
}

Kompilator gwarantuje, że podczas obliczania wyrażenia == nie jest wywoływany żaden operator x is null równości przeciążony przez użytkownika.

Możesz użyć negowanego wzorca stałej null, aby sprawdzić, czy nie ma wartości null, jak pokazano w poniższym przykładzie:

if (input is not null)
{
    // ...
}

Aby uzyskać więcej informacji, zobacz sekcję Stały wzorzec notatki dotyczącej propozycji funkcji.

Wzorce relacyjne

Wzorzec relacyjny służy do porównywania wyniku wyrażenia z stałą, jak pokazano w poniższym przykładzie:

Console.WriteLine(Classify(13));  // output: Too high
Console.WriteLine(Classify(double.NaN));  // output: Unknown
Console.WriteLine(Classify(2.4));  // output: Acceptable

static string Classify(double measurement) => measurement switch
{
    < -4.0 => "Too low",
    > 10.0 => "Too high",
    double.NaN => "Unknown",
    _ => "Acceptable",
};

We wzorcu relacyjnym można użyć dowolnych operatorów <relacyjnych , >, <=lub .>= Prawa część wzorca relacyjnego musi być wyrażeniem stałym. Wyrażenie stałe może być liczbą całkowitą, zmiennoprzecinkową, znakiem lub typem wyliczeniowym .

Aby sprawdzić, czy wynik wyrażenia znajduje się w określonym zakresie, dopasuj go do and sprzężonego, jak pokazano w poniższym przykładzie:

Console.WriteLine(GetCalendarSeason(new DateTime(2021, 3, 14)));  // output: spring
Console.WriteLine(GetCalendarSeason(new DateTime(2021, 7, 19)));  // output: summer
Console.WriteLine(GetCalendarSeason(new DateTime(2021, 2, 17)));  // output: winter

static string GetCalendarSeason(DateTime date) => date.Month switch
{
    >= 3 and < 6 => "spring",
    >= 6 and < 9 => "summer",
    >= 9 and < 12 => "autumn",
    12 or (>= 1 and < 3) => "winter",
    _ => throw new ArgumentOutOfRangeException(nameof(date), $"Date with unexpected month: {date.Month}."),
};

Jeśli wynik wyrażenia jest null lub nie można przekonwertować na typ stałej przez konwersję dopuszczającą wartość null lub rozpatową, wzorzec relacyjny nie jest zgodny z wyrażeniem.

Aby uzyskać więcej informacji, zobacz sekcję Relacyjne wzorce w notatce dotyczącej propozycji funkcji.

Wzorce logiczne

notKombinatory wzorców , andi or służą do tworzenia następujących wzorców logicznych:

  • Wzorzec negacjinot zgodny z wyrażeniem, gdy negowany wzorzec nie jest zgodny z wyrażeniem. W poniższym przykładzie pokazano, jak można negować null stały wzorzec, aby sprawdzić, czy wyrażenie ma wartość inną niż null:

    if (input is not null)
    {
        // ...
    }
    
  • Wzorzec conjunctiveand, który pasuje do wyrażenia, gdy oba wzorce pasują do wyrażenia. W poniższym przykładzie pokazano, jak połączyć wzorce relacyjne, aby sprawdzić, czy wartość znajduje się w określonym zakresie:

    Console.WriteLine(Classify(13));  // output: High
    Console.WriteLine(Classify(-100));  // output: Too low
    Console.WriteLine(Classify(5.7));  // output: Acceptable
    
    static string Classify(double measurement) => measurement switch
    {
        < -40.0 => "Too low",
        >= -40.0 and < 0 => "Low",
        >= 0 and < 10.0 => "Acceptable",
        >= 10.0 and < 20.0 => "High",
        >= 20.0 => "Too high",
        double.NaN => "Unknown",
    };
    
  • Wzorzec disjunctiveor, który pasuje do wyrażenia, gdy dowolny wzorzec pasuje do wyrażenia, jak pokazano w poniższym przykładzie:

    Console.WriteLine(GetCalendarSeason(new DateTime(2021, 1, 19)));  // output: winter
    Console.WriteLine(GetCalendarSeason(new DateTime(2021, 10, 9)));  // output: autumn
    Console.WriteLine(GetCalendarSeason(new DateTime(2021, 5, 11)));  // output: spring
    
    static string GetCalendarSeason(DateTime date) => date.Month switch
    {
        3 or 4 or 5 => "spring",
        6 or 7 or 8 => "summer",
        9 or 10 or 11 => "autumn",
        12 or 1 or 2 => "winter",
        _ => throw new ArgumentOutOfRangeException(nameof(date), $"Date with unexpected month: {date.Month}."),
    };
    

Jak pokazano w poprzednim przykładzie, można wielokrotnie używać kombinatorów wzorców we wzorcu.

Pierwszeństwo i kolejność sprawdzania

Kombinatory wzorców są uporządkowane na podstawie kolejności powiązań wyrażeń w następujący sposób:

  • not
  • and
  • or

Wzorzec not wiąże się najpierw z operandem. Wzorzec and jest powiązany po każdym not powiązaniu wyrażenia wzorca. Wzorzec or wiąże się po wszystkich not wzorcach i and z operandami. Poniższy przykład próbuje dopasować wszystkie znaki, które nie są małymi literami, a - z. Występuje błąd, ponieważ not wzorzec wiąże się przed wzorcem and :

// Incorrect pattern. `not` binds before `and`
static bool IsNotLowerCaseLetter(char c) => c is not >= 'a' and <= 'z';

Powiązanie domyślne oznacza, że poprzedni przykład jest analizowany jako poniższy przykład:

// The default binding without parentheses is shows in this method. `not` binds before `and`
static bool IsNotLowerCaseLetterDefaultBinding(char c) => c is ((not >= 'a') and <= 'z');

Aby rozwiązać ten problem, należy określić, że element not ma zostać powiązany z wyrażeniem >= 'a' and <= 'z' :

// Correct pattern. Force `and` before `not`
static bool IsNotLowerCaseLetterParentheses(char c) => c is not (>= 'a' and <= 'z');

Dodawanie nawiasów staje się ważniejsze, ponieważ wzorce stają się bardziej skomplikowane. Ogólnie rzecz biorąc, użyj nawiasów, aby wyjaśnić wzorce dla innych deweloperów, jak pokazano w poniższym przykładzie:

static bool IsLetter(char c) => c is (>= 'a' and <= 'z') or (>= 'A' and <= 'Z');

Uwaga

Kolejność sprawdzania wzorców mających tę samą kolejność powiązania jest niezdefiniowana. W czasie wykonywania można najpierw sprawdzić zagnieżdżone wzorce z prawej strony wielu or wzorców i wiele and wzorców.

Aby uzyskać więcej informacji, zobacz sekcję Kombinatory wzorców w notatce propozycji funkcji.

Wzorzec właściwości

Wzorzec właściwości służy do dopasowywania właściwości lub pól wyrażenia do zagnieżdżonych wzorców, jak pokazano w poniższym przykładzie:

static bool IsConferenceDay(DateTime date) => date is { Year: 2020, Month: 5, Day: 19 or 20 or 21 };

Wzorzec właściwości pasuje do wyrażenia, gdy wynik wyrażenia jest inny niż null, a każdy zagnieżdżony wzorzec pasuje do odpowiedniej właściwości lub pola wyniku wyrażenia.

Można również dodać sprawdzanie typu czasu wykonywania i deklarację zmiennej do wzorca właściwości, jak pokazano w poniższym przykładzie:

Console.WriteLine(TakeFive("Hello, world!"));  // output: Hello
Console.WriteLine(TakeFive("Hi!"));  // output: Hi!
Console.WriteLine(TakeFive(new[] { '1', '2', '3', '4', '5', '6', '7' }));  // output: 12345
Console.WriteLine(TakeFive(new[] { 'a', 'b', 'c' }));  // output: abc

static string TakeFive(object input) => input switch
{
    string { Length: >= 5 } s => s.Substring(0, 5),
    string s => s,

    ICollection<char> { Count: >= 5 } symbols => new string(symbols.Take(5).ToArray()),
    ICollection<char> symbols => new string(symbols.ToArray()),

    null => throw new ArgumentNullException(nameof(input)),
    _ => throw new ArgumentException("Not supported input type."),
};

Wzorzec właściwości jest wzorcem rekursywnym. Oznacza to, że można użyć dowolnego wzorca jako wzorca zagnieżdżonego. Użyj wzorca właściwości, aby dopasować części danych do zagnieżdżonych wzorców, jak pokazano w poniższym przykładzie:

public record Point(int X, int Y);
public record Segment(Point Start, Point End);

static bool IsAnyEndOnXAxis(Segment segment) =>
    segment is { Start: { Y: 0 } } or { End: { Y: 0 } };

W poprzednim przykładzie użyto kombinatora orwzorca i typów rekordów.

Można odwoływać się do zagnieżdżonych właściwości lub pól w szablonie właściwości. Ta funkcja jest znana jako wzorzec rozszerzonej właściwości. Na przykład można refaktoryzować metodę z poprzedniego przykładu do następującego równoważnego kodu:

static bool IsAnyEndOnXAxis(Segment segment) =>
    segment is { Start.Y: 0 } or { End.Y: 0 };

Aby uzyskać więcej informacji, zobacz sekcję Wzorzec właściwości w notatce propozycji funkcji i notatce propozycji funkcji Rozszerzone wzorce właściwości.

Napiwek

Aby zwiększyć czytelność kodu, można użyć reguły stylu Upraszczanie wzorca właściwości (IDE0170), sugerując miejsca do używania rozszerzonych wzorców właściwości.

Wzorzec pozycyjny

Wzorzec pozycyjny służy do dekonstrukcji wyniku wyrażenia i dopasowywania wartości wynikowych do odpowiednich zagnieżdżonych wzorców, jak pokazano w poniższym przykładzie:

public readonly struct 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);
}

static string Classify(Point point) => point switch
{
    (0, 0) => "Origin",
    (1, 0) => "positive X basis end",
    (0, 1) => "positive Y basis end",
    _ => "Just a point",
};

W poprzednim przykładzie typ wyrażenia zawiera metodę Deconstruct, która służy do dekonstrukcji wyniku wyrażenia.

Ważne

Kolejność elementów członkowskich we wzorcu pozycyjnym musi być zgodna z kolejnością parametrów w metodzie Deconstruct . Dzieje się tak, ponieważ kod wygenerowany dla wzorca pozycyjnego wywołuje metodę Deconstruct .

Można również dopasować wyrażenia typów krotki względem wzorców pozycyjnych. W ten sposób można dopasować wiele danych wejściowych do różnych wzorców, jak pokazano w poniższym przykładzie:

static decimal GetGroupTicketPriceDiscount(int groupSize, DateTime visitDate)
    => (groupSize, visitDate.DayOfWeek) switch
    {
        (<= 0, _) => throw new ArgumentException("Group size must be positive."),
        (_, DayOfWeek.Saturday or DayOfWeek.Sunday) => 0.0m,
        (>= 5 and < 10, DayOfWeek.Monday) => 20.0m,
        (>= 10, DayOfWeek.Monday) => 30.0m,
        (>= 5 and < 10, _) => 12.0m,
        (>= 10, _) => 15.0m,
        _ => 0.0m,
    };

W poprzednim przykładzie użyto wzorców relacyjnych i logicznych .

Nazwy elementów krotki i Deconstruct parametrów można używać w wzorcu pozycyjnym, jak pokazano w poniższym przykładzie:

var numbers = new List<int> { 1, 2, 3 };
if (SumAndCount(numbers) is (Sum: var sum, Count: > 0))
{
    Console.WriteLine($"Sum of [{string.Join(" ", numbers)}] is {sum}");  // output: Sum of [1 2 3] is 6
}

static (double Sum, int Count) SumAndCount(IEnumerable<int> numbers)
{
    int sum = 0;
    int count = 0;
    foreach (int number in numbers)
    {
        sum += number;
        count++;
    }
    return (sum, count);
}

Można również rozszerzyć wzorzec pozycyjny na dowolny z następujących sposobów:

  • Dodaj sprawdzanie typu czasu wykonywania i deklarację zmiennej, jak pokazano w poniższym przykładzie:

    public record Point2D(int X, int Y);
    public record Point3D(int X, int Y, int Z);
    
    static string PrintIfAllCoordinatesArePositive(object point) => point switch
    {
        Point2D (> 0, > 0) p => p.ToString(),
        Point3D (> 0, > 0, > 0) p => p.ToString(),
        _ => string.Empty,
    };
    

    W poprzednim przykładzie użyto rekordów pozycyjnych, które niejawnie udostępniają metodę Deconstruct .

  • Użyj wzorca właściwości w ramach wzorca pozycyjnego, jak pokazano w poniższym przykładzie:

    public record WeightedPoint(int X, int Y)
    {
        public double Weight { get; set; }
    }
    
    static bool IsInDomain(WeightedPoint point) => point is (>= 0, >= 0) { Weight: >= 0.0 };
    
  • Połącz dwa poprzednie użycia, jak pokazano w poniższym przykładzie:

    if (input is WeightedPoint (> 0, > 0) { Weight: > 0.0 } p)
    {
        // ..
    }
    

Wzorzec pozycyjny jest wzorcem rekursywnym. Oznacza to, że można użyć dowolnego wzorca jako wzorca zagnieżdżonego.

Aby uzyskać więcej informacji, zobacz sekcję Wzorzec pozycyjny uwagi dotyczącej propozycji funkcji.

var deseń

Wzorzecvar do dopasowania dowolnego wyrażenia, w tym null, i przypisania jego wyniku do nowej zmiennej lokalnej, jak pokazano w poniższym przykładzie:

static bool IsAcceptable(int id, int absLimit) =>
    SimulateDataFetch(id) is var results 
    && results.Min() >= -absLimit 
    && results.Max() <= absLimit;

static int[] SimulateDataFetch(int id)
{
    var rand = new Random();
    return Enumerable
               .Range(start: 0, count: 5)
               .Select(s => rand.Next(minValue: -10, maxValue: 11))
               .ToArray();
}

var Wzorzec jest przydatny, gdy potrzebna jest zmienna tymczasowa w wyrażeniu logicznym do przechowywania wyniku obliczeń pośrednich. Można również użyć var wzorca, gdy trzeba wykonać więcej kontroli w when przypadku ochrony switch wyrażenia lub instrukcji, jak pokazano w poniższym przykładzie:

public record Point(int X, int Y);

static Point Transform(Point point) => point switch
{
    var (x, y) when x < y => new Point(-x, y),
    var (x, y) when x > y => new Point(x, -y),
    var (x, y) => new Point(x, y),
};

static void TestTransform()
{
    Console.WriteLine(Transform(new Point(1, 2)));  // output: Point { X = -1, Y = 2 }
    Console.WriteLine(Transform(new Point(5, 2)));  // output: Point { X = 5, Y = -2 }
}

W poprzednim przykładzie wzorzec var (x, y) jest odpowiednikiem wzorca(var x, var y).

var We wzorcu typ zadeklarowanej zmiennej jest typem czasu kompilacji wyrażenia dopasowanego do wzorca.

Aby uzyskać więcej informacji, zobacz sekcję Var pattern (Wzorzec wariancji ) notatki dotyczącej propozycji funkcji.

Odrzuć wzorzec

Wzorzec_do dopasowania do dowolnego wyrażenia, w tym null, jak pokazano w poniższym przykładzie:

Console.WriteLine(GetDiscountInPercent(DayOfWeek.Friday));  // output: 5.0
Console.WriteLine(GetDiscountInPercent(null));  // output: 0.0
Console.WriteLine(GetDiscountInPercent((DayOfWeek)10));  // output: 0.0

static decimal GetDiscountInPercent(DayOfWeek? dayOfWeek) => dayOfWeek switch
{
    DayOfWeek.Monday => 0.5m,
    DayOfWeek.Tuesday => 12.5m,
    DayOfWeek.Wednesday => 7.5m,
    DayOfWeek.Thursday => 12.5m,
    DayOfWeek.Friday => 5.0m,
    DayOfWeek.Saturday => 2.5m,
    DayOfWeek.Sunday => 2.0m,
    _ => 0.0m,
};

W poprzednim przykładzie wzorzec odrzucenia jest używany do obsługi null wszystkich wartości całkowitych, które nie mają odpowiedniego DayOfWeek elementu członkowskiego wyliczenia. Gwarantuje to, że switch wyrażenie w przykładzie obsługuje wszystkie możliwe wartości wejściowe. Jeśli nie używasz wzorca odrzucenia w wyrażeniu switch i żaden z wzorców wyrażenia nie pasuje do danych wejściowych, środowisko uruchomieniowe zgłasza wyjątek. Kompilator generuje ostrzeżenie, jeśli switch wyrażenie nie obsługuje wszystkich możliwych wartości wejściowych.

Wzorzec odrzucenia nie może być wzorcem w wyrażeniu is ani instrukcji switch . W takich przypadkach, aby dopasować dowolne wyrażenie, użyj var wzorca z odrzuceniem: var _. Wzorzec odrzucenia może być wzorcem w wyrażeniu switch .

Aby uzyskać więcej informacji, zobacz sekcję Odrzuć wzorzec notatki dotyczącej propozycji funkcji.

Wzorzec nawiasów

Nawiasy można umieścić wokół dowolnego wzorca. Zazwyczaj należy to zrobić, aby podkreślić lub zmienić pierwszeństwo we wzorcach logicznych, jak pokazano w poniższym przykładzie:

if (input is not (float or double))
{
    return;
}

Wzorce listy

Począwszy od języka C# 11, można dopasować tablicę lub listę do sekwencji wzorców, jak pokazano w poniższym przykładzie:

int[] numbers = { 1, 2, 3 };

Console.WriteLine(numbers is [1, 2, 3]);  // True
Console.WriteLine(numbers is [1, 2, 4]);  // False
Console.WriteLine(numbers is [1, 2, 3, 4]);  // False
Console.WriteLine(numbers is [0 or 1, <= 2, >= 3]);  // True

Jak pokazano w poprzednim przykładzie, wzorzec listy jest dopasowywany, gdy każdy zagnieżdżony wzorzec pasuje do odpowiedniego elementu sekwencji danych wejściowych. W ramach wzorca listy można użyć dowolnego wzorca. Aby dopasować dowolny element, użyj wzorca odrzucenia lub, jeśli chcesz również przechwycić element, wzorzec var, jak pokazano w poniższym przykładzie:

List<int> numbers = new() { 1, 2, 3 };

if (numbers is [var first, _, _])
{
    Console.WriteLine($"The first element of a three-item list is {first}.");
}
// Output:
// The first element of a three-item list is 1.

Powyższe przykłady pasują do całej sekwencji danych wejściowych względem wzorca listy. Aby dopasować elementy tylko na początku lub/i końcu sekwencji wejściowej, użyj wzorca..wycinka , jak pokazano w poniższym przykładzie:

Console.WriteLine(new[] { 1, 2, 3, 4, 5 } is [> 0, > 0, ..]);  // True
Console.WriteLine(new[] { 1, 1 } is [_, _, ..]);  // True
Console.WriteLine(new[] { 0, 1, 2, 3, 4 } is [> 0, > 0, ..]);  // False
Console.WriteLine(new[] { 1 } is [1, 2, ..]);  // False

Console.WriteLine(new[] { 1, 2, 3, 4 } is [.., > 0, > 0]);  // True
Console.WriteLine(new[] { 2, 4 } is [.., > 0, 2, 4]);  // False
Console.WriteLine(new[] { 2, 4 } is [.., 2, 4]);  // True

Console.WriteLine(new[] { 1, 2, 3, 4 } is [>= 0, .., 2 or 4]);  // True
Console.WriteLine(new[] { 1, 0, 0, 1 } is [1, 0, .., 0, 1]);  // True
Console.WriteLine(new[] { 1, 0, 1 } is [1, 0, .., 0, 1]);  // False

Wzorzec wycinka pasuje do zera lub większej liczby elementów. W wzorcu listy można użyć co najwyżej jednego wzorca wycinka. Wzorzec wycinka może być wyświetlany tylko we wzorcu listy.

Można również zagnieżdżać podwzorca we wzorcu wycinka, jak pokazano w poniższym przykładzie:

void MatchMessage(string message)
{
    var result = message is ['a' or 'A', .. var s, 'a' or 'A']
        ? $"Message {message} matches; inner part is {s}."
        : $"Message {message} doesn't match.";
    Console.WriteLine(result);
}

MatchMessage("aBBA");  // output: Message aBBA matches; inner part is BB.
MatchMessage("apron");  // output: Message apron doesn't match.

void Validate(int[] numbers)
{
    var result = numbers is [< 0, .. { Length: 2 or 4 }, > 0] ? "valid" : "not valid";
    Console.WriteLine(result);
}

Validate(new[] { -1, 0, 1 });  // output: not valid
Validate(new[] { -1, 0, 0, 1 });  // output: valid

Aby uzyskać więcej informacji, zobacz notatkę dotyczącą propozycji funkcji Wzorce listy.

specyfikacja języka C#

Aby uzyskać więcej informacji, zobacz sekcję Wzorce i dopasowywanie wzorców specyfikacji języka C#.

Aby uzyskać informacje o funkcjach dodanych w języku C# 8 lub nowszym, zobacz następujące uwagi dotyczące propozycji funkcji:

Zobacz też