Dopasowywanie wzorca — is
wyrażenia i switch
oraz operatory and
, or
i 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
, or
i 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 interfejsT
lub inną niejawną konwersję odwołania istnieje z niego doT
. 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ż typint[]
czasu wykonywania argumentu Array pochodzi z typu . W drugim wywołaniuGetSourceLabel
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:
- liczba całkowita lub literał liczbowy zmiennoprzecinkowa
- znak
- literał ciągu .
- wartość
true
logiczna lubfalse
- wartość wyliczenia
- nazwa zadeklarowanego pola const lub lokalnego
null
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ć , null
jak 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
not
Kombinatory wzorców , and
i or
służą do tworzenia następujących wzorców logicznych:
Wzorzec negacji
not
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 conjunctive
and
, 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 disjunctive
or
, 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 or
wzorca 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:
- Cykliczne dopasowywanie wzorca
- Aktualizacje dopasowywania wzorca
- rozszerzone wzorce właściwości
- C# 11 — wzorce listy
-
C# 11 — dopasowanie
Span<char>
wzorca literału ciągu