Freigeben über


Musterabgleich - die is Ausdrücke und switch Operatoren and, orund not in Mustern

Sie verwenden den is Ausdruck, die Switch-Anweisung und den Switch-Ausdruck , um einem Eingabeausdruck eine beliebige Anzahl von Merkmalen zuzuordnen. C# unterstützt mehrere Muster, einschließlich „Typ“, „Konstante“, „relational“, „Eigenschaft“, „Liste“, „var“ und „Ausschuss“. Muster können mit den booleschen Logikschlüsselwörtern and, or und not kombiniert werden.

Die folgenden C#-Ausdrücke und -Anweisungen unterstützen Musterabgleiche:

In diesen Konstrukten können Sie einen Eingabeausdruck gegen jedes der folgenden Muster abgleichen:

  • Deklarationsmuster: um den Laufzeittyp eines Ausdrucks zu überprüfen und bei einem erfolgreichen Abgleich einer deklarierten Variable ein Ausdrucksergebnis zuzuweisen.
  • Typmuster: um den Laufzeittyp eines Ausdrucks zu überprüfen.
  • Konstantenmuster: Um zu testen, dass ein Ausdrucksergebnis einer angegebenen Konstante entspricht.
  • Relationale Muster: um ein Ausdrucksergebnis mit einer angegebenen Konstante zu vergleichen.
  • Logische Muster: Um zu testen, dass ein Ausdruck einer logischen Kombination von Mustern entspricht.
  • Eigenschaftenmuster: Um zu testen, dass die Eigenschaften oder Felder eines Ausdrucks geschachtelten Mustern entsprechen.
  • Positionsmuster: um ein Ausdrucksergebnis zu dekonstruieren und zu testen, ob die resultierenden Werte mit geschachtelten Mustern übereinstimmen.
  • var-Muster: um einen beliebigen Ausdruck abzugleichen und dessen Ergebnis einer deklarierten Variablen zuzuweisen.
  • Ausschussmuster: um einen beliebigen Ausdruck abzugleichen.
  • Listenmuster: Um zu testen, dass eine Abfolge von Elementen den entsprechenden geschachtelten Mustern entspricht. Eingeführt in C# 11.

Die Muster logisch, Eigenschaft, positionell und Liste sind rekursive Muster. Das heißt, Sie können geschachtelte Muster enthalten.

Ein Beispiel dazu, wie diese Muster verwendet werden, um einen datengesteuerten Algorithmus zu erstellen, finden Sie unter Tutorial: Verwenden von Musterabgleich, um typgesteuerte und datengesteuerte Algorithmen zu erstellen.

Deklarations- und Typmuster

Sie können Deklarations- und Typmuster verwenden, um zu prüfen, ob der Laufzeittyp eines Ausdrucks mit einem angegebenen Typ kompatibel ist. Mit einem Deklarationsmuster können Sie auch eine neue lokale Variable deklarieren. Wenn ein Deklarationsmuster mit einem Ausdruck übereinstimmt, wird dieser Variablen ein konvertiertes Ausdrucksergebnis zugewiesen, wie im folgenden Beispiel gezeigt:

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

Ein Deklarationsmuster mit dem Typ T entspricht einem Ausdruck, wenn ein Ausdrucksergebnis nicht NULL ist und eine der folgenden Bedingungen zutrifft:

  • Der Laufzeittyp eines Ausdrucksergebnisses ist T.

  • Der Laufzeittyp eines Ausdrucksergebnisses wird vom Typ T abgeleitet, oder er implementiert die T-Schnittstelle, oder es gibt eine andere implizite Verweiskonvertierung von diesem Typ zu T. Das folgende Beispiel zeigt zwei Fälle, in denen diese Bedingung whr ist:

    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,
    };
    

    Im vorangehenden Beispiel entspricht das erste Muster im ersten Aufruf der GetSourceLabel-Methode einem Argumentwert, da der Laufzeittyp int[] des Arguments vom Typ Array abgeleitet wird. Im zweiten Aufruf der GetSourceLabel-Methode wird der Laufzeittyp List<T> des Arguments nicht vom Typ Array abgeleitet, er implementiert aber die ICollection<T>-Schnittstelle.

  • Der Laufzeittyp eines Ausdrucksergebnisses ist ein Nullwerte zulassender Typ mit dem zugrunde liegenden Typ T.

  • Eine Boxing- oder Unboxing-Konvertierung ist vom Laufzeittyp eines Ausdrucksergebnisses bis zum Typ T vorhanden.

Im folgenden Beispiel werden die beiden letzten Bedingungen veranschaulicht:

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

Wenn Sie nur den Typ eines Ausdrucks überprüfen möchten, können Sie eine Ausschussvariable _ anstelle des Namens einer Variablen verwenden, wie im folgenden Beispiel gezeigt:

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)),
    };
}

Sie können zu diesem Zweck ein Typmusterverwenden, wie im folgenden Beispiel gezeigt:

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)),
};

Wie ein Deklarationsmuster entspricht ein Typmuster einem Ausdruck, wenn ein Ausdrucksergebnis ungleich NULL ist und sein Laufzeittyp eine der vorherigen Bedingungen erfüllt.

Um nach Werten ungleich NULL zu suchen, können Sie ein negiertes null -Konstantenmuster wie im folgenden Beispiel verwenden.

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

Weitere Informationen finden Sie in den Abschnitten Deklarationsmuster und Typmuster der Hinweise zum Featurevorschlag.

Konstantenmuster

Sie verwenden ein Konstantenmuster, um zu testen, ob ein Ausdrucksergebnis einer angegebenen Konstante entspricht, wie im folgenden Beispiel gezeigt:

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)),
};

In einem Konstantenmuster können Sie einen beliebigen konstanten Ausdruck verwenden, z. B.:

  • ein numerisches Literal mit integralem oder Gleitkomma-Typ
  • Ein char
  • Ein string-Literal (Zeichenfolgenliteral)
  • ein boolescher Wert true oder false
  • ein enum-Wert
  • der Name eines deklarierten const-Felds oder lokalen const-Ausdrucks
  • null

Der Ausdruck muss ein Typ sein, der in den Konstantentyp konvertiert werden kann, mit einer Ausnahme: Ein Ausdruck, dessen Typ Span<char> oder ReadOnlySpan<char> ist und mit konstanten Zeichenfolgen in C# 11 und höheren Versionen abgeglichen werden kann.

Verwenden Sie ein Konstantenmuster, um auf null zu prüfen, wie im folgenden Beispiel gezeigt:

if (input is null)
{
    return;
}

Der Compiler stellt sicher, dass kein vom Benutzer überladener Gleichheitsoperator == aufgerufen wird, wenn der Ausdruck x is null ausgewertet wird.

Sie können ein negiertes null-Konstantenmuster verwenden, um auf Werte ungleich NULL zu prüfen, wie im folgenden Beispiel gezeigt:

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

Weitere Informationen finden Sie im Abschnitt Konstantenmuster des Hinweises zum Featurevorschlag.

Relationale Muster

Sie verwenden ein relationales Muster, um ein Ausdrucksergebnis mit einer Konstante zu vergleichen, wie im folgenden Beispiel gezeigt:

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",
};

In einem relationalen Muster können Sie jeden der relationalen Operatoren <, >, <= oder >= verwenden. Der rechte Teil eines relationalen Musters muss ein konstanter Ausdruck sein. Der Konstantenausdruck kann einen der integralen, Gleitkomma-, char- oder enum-Typen haben.

Um zu überprüfen, ob sich ein Ausdrucksergebnis in einem bestimmten Bereich befindet, gleichen Sie es mit einem konjunktiven and-Muster ab, wie im folgenden Beispiel gezeigt:

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}."),
};

Wenn ein Ausdrucksergebnis gleich null ist oder in einer Nullwerte zulassenden oder Unboxing-Konvertierung nicht in den Typ einer Konstante konvertiert werden kann, entspricht ein relationales Muster keinem Ausdruck.

Weitere Informationen finden Sie im Abschnitt Relationale Muster des Hinweises zum Featurevorschlag.

Logische Muster

Sie verwenden die not-, and- und or-Musterkombinatoren, um die folgenden logischen Muster zu erstellen:

  • Negations-not-Muster, das mit einem Ausdruck übereinstimmt, wenn das negierte Muster nicht mit dem Ausdruck übereinstimmt. Das folgende Beispiel zeigt, wie Sie ein konstantes null-Muster negieren können, um zu überprüfen, ob ein Ausdruck ungleich NULL ist:

    if (input is not null)
    {
        // ...
    }
    
  • Konjunktives and-Muster, das mit einem Ausdruck übereinstimmt, wenn beide Muster mit dem Ausdruck übereinstimmen. Im folgenden Beispiel wird gezeigt, wie Sie relationale Muster kombinieren können, um zu überprüfen, ob ein Wert in einem bestimmten Bereich liegt:

    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",
    };
    
  • Disjunktives or-Muster, das mit einem Ausdruck übereinstimmt, wenn eines der Muster mit dem Ausdruck übereinstimmt, wie im folgenden Beispiel gezeigt:

    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}."),
    };
    

Wie das vorherige Beispiel zeigt, können Sie die Musterkombinatoren wiederholt in einem Muster verwenden.

Vorrang und Auswertungsreihenfolge

Die Musterkombinatoren werden basierend auf der Bindungsreihenfolge von Ausdrücken wie folgt sortiert:

  • not
  • and
  • or

Das not Muster wird zuerst an den Operanden gebunden. Das and Muster wird nach einer not Musterausdrucksbindung gebunden. Das or Muster wird gebunden, nachdem alle not Muster and an Operanden gebunden sind. Im folgenden Beispiel wird versucht, alle Zeichen abzugleichen, die keine Kleinbuchstaben sind. a - z Es hat einen Fehler, da das not Muster vor dem and Muster gebunden wird:

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

Die Standardbindung bedeutet, dass das vorherige Beispiel wie im folgenden Beispiel analysiert wird:

// 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');

Um dies zu beheben, müssen Sie angeben, dass die not Bindung an den >= 'a' and <= 'z' Ausdruck erfolgen soll:

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

Das Hinzufügen von Klammern wird wichtiger, da Ihre Muster komplizierter werden. Verwenden Sie im Allgemeinen Klammern, um Ihre Muster für andere Entwickler zu verdeutlichen, wie das folgende Beispiel zeigt:

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

Hinweis

Die Reihenfolge, in der Muster mit derselben Bindungsreihenfolge überprüft werden, ist nicht definiert. Zur Laufzeit können die rechts geschachtelten Muster mehrerer or Muster und mehrere and Muster zuerst überprüft werden.

Weitere Informationen finden Sie im Abschnitt Musterkombinatoren des Hinweises zum Featurevorschlag.

Eigenschaftsmuster

Sie verwenden ein Eigenschaftsmuster, um die Eigenschaften oder Felder eines Ausdrucks mit den geschachtelten Mustern abzugleichen, wie im folgenden Beispiel gezeigt:

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

Ein Eigenschaftsmuster stimmt mit einem Ausdruck überein, wenn ein Ausdrucksergebnis nicht NULL ist und jedes geschachtelte Muster mit der entsprechenden Eigenschaft oder dem entsprechenden Feld des Ausdrucksergebnisses übereinstimmt.

Sie können einem Eigenschaftsmuster auch eine Laufzeittypüberprüfung und eine Variablendeklaration hinzufügen, wie im folgenden Beispiel gezeigt:

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."),
};

Ein Eigenschaftsmuster ist ein rekursives Muster. Das heißt, Sie können ein beliebiges Muster als ein geschachteltes Muster verwenden. Verwenden Sie ein Eigenschaftsmuster, um Teile von Daten gegen geschachtelte Muster abzugleichen, wie im folgenden Beispiel gezeigt:

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 } };

Im vorherigen Beispiel werden der Musterkombinator or und Datensatztypen verwendet.

Ab C# 10 können Sie auf geschachtelte Eigenschaften oder Felder innerhalb eines Eigenschaftsmusters verweisen. Diese Funktion wird als erweitertes Eigenschaftenmuster bezeichnet. Beispielsweise können Sie die Methode aus dem vorherigen Beispiel in den folgenden äquivalenten Code umgestalten:

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

Weitere Informationen finden Sie im Abschnitt Eigenschaftenmuster des Hinweises zum Featurevorschlag sowie im Hinweis zum Featurevorschlag Muster für erweiterte Eigenschaften.

Tipp

Sie können die Stilregel Eigenschaftenmuster vereinfachen (IDE0170) verwenden, um die Lesbarkeit von Code zu verbessern, indem Sie vorschlagen, wo erweiterte Eigenschaftenmuster verwendet werden sollen.

Positionsmuster

Sie verwenden ein Positionsmuster, um ein Ausdrucksergebnis zu dekonstruieren und die resultierenden Werte mit den entsprechenden geschachtelten Muster abzugleichen, wie im folgenden Beispiel gezeigt:

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",
};

Im vorherigen Beispiel enthält der Typ eines Ausdrucks die Deconstruct-Methode, die zum Dekonstruieren eines Ausdrucksergebnisses verwendet wird.

Wichtig

Die Reihenfolge der Elemente in einem Positionsmuster muss mit der Reihenfolge der Parameter in der Deconstruct-Methode übereinstimmen. Dies liegt daran, dass der für das Positionsmuster generierte Code die Deconstruct-Methode aufruft.

Sie können auch Ausdrücke von Tupeltypen gegen Positionsmuster abgleichen. Auf diese Weise können Sie mehrere Eingaben gegen verschiedene Muster abgleichen, wie im folgenden Beispiel gezeigt:

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,
    };

Im vorherigen Beispiel werden relationale und logische Muster verwendet.

Sie können die Namen von Tupelelementen und Deconstruct-Parametern in einem Positionsmuster verwenden, wie im folgenden Beispiel gezeigt:

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);
}

Sie können ein Positionsmuster auch auf eine der folgenden Arten erweitern:

  • Fügen Sie eine Laufzeittypüberprüfung und eine Variablendeklaration hinzu, wie im folgenden Beispiel gezeigt:

    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,
    };
    

    Im vorherigen Beispiel werden Datensätze mit Feldern fester Breite verwendet, die implizit die Deconstruct-Methode bereitstellen.

  • Verwenden Sie ein Eigenschaftsmuster in einem Positionsmuster, wie im folgenden Beispiel gezeigt:

    public record WeightedPoint(int X, int Y)
    {
        public double Weight { get; set; }
    }
    
    static bool IsInDomain(WeightedPoint point) => point is (>= 0, >= 0) { Weight: >= 0.0 };
    
  • Kombinieren Sie zwei vorangehende Verwendungen, wie im folgenden Beispiel gezeigt:

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

Ein Positionsmuster ist ein rekursives Muster. Das heißt, Sie können ein beliebiges Muster als ein geschachteltes Muster verwenden.

Weitere Informationen finden Sie im Abschnitt Positionsmuster des Hinweises zum Featurevorschlag.

var-Muster

Sie verwenden ein var-Muster, um einen beliebigen Ausdruck, einschließlich null, abzugleichen und dessen Ergebnis einer neuen lokalen Variablen zuzuweisen, wie im folgenden Beispiel gezeigt:

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();
}

Ein var-Muster ist nützlich, wenn Sie eine temporäre Variable in einem booleschen Ausdruck benötigen, um das Ergebnis von Zwischenberechnungen zu speichern. Sie können ein var-Muster auch verwenden, wenn Sie weitere Überprüfungen in den when-Ausdrücken eines switch-Ausdrucks oder einer switch-Anweisung ausführen müssen, wie im folgenden Beispiel gezeigt:

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 }
}

Im vorherigen Beispiel ist das Muster var (x, y) gleichwertig mit einem Positionsmuster (var x, var y).

In einem var-Muster ist der Typ einer deklarierten Variablen der Kompilierzeittyp des Ausdrucks, der gegen das Muster abgeglichen wird.

Weitere Informationen finden Sie im Abschnitt Var-Muster des Hinweises zum Featurevorschlag.

Ausschussmuster

Sie verwenden ein Ausschussmuster _, um einen beliebigen Ausdruck, einschließlich null, abzugleichen, wie im folgenden Beispiel gezeigt:

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,
};

Im vorherigen Beispiel wird ein Ausschussmuster verwendet, um null und jeden ganzzahligen Wert zu verarbeiten, der nicht den entsprechenden Member der DayOfWeek-Enumeration hat. Dadurch wird sichergestellt, dass ein switch-Ausdruck im Beispiel alle möglichen Eingabewerte verarbeitet. Wenn Sie kein Ausschussmuster in einem switch-Ausdruck verwenden und keines der Muster des Ausdrucks mit einer Eingabe übereinstimmt, löst die Runtime eine Ausnahme aus. Der Compiler generiert eine Warnung, wenn ein switch-Ausdruck nicht alle möglichen Eingabewerte verarbeiten kann.

Ein Ausschussmuster kann kein Muster in einem is-Ausdruck oder in einer switch-Anweisung sein. Verwenden Sie in diesen Fällen, um einen Ausdruck abzugleichen, ein var-Muster mit einem Ausschussmuster: var _. Ein Ausschussmuster kann kein Muster in einem switch-Ausdruck sein.

Weitere Informationen finden Sie im Abschnitt Ausschussmuster des Hinweises zum Featurevorschlag.

Muster in Klammern

Sie können Klammern um ein beliebiges Muster setzen. In der Regel tun Sie dies, um die Rangfolge in logischen Mustern hervorzuheben oder zu ändern, wie im folgenden Beispiel gezeigt:

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

Listenmuster

Ab C# 11 können Sie ein Array oder eine Liste mit einer Abfolge von Mustern abgleichen, wie im folgenden Beispiel gezeigt:

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

Wie im vorherigen Beispiel gezeigt, wird ein Listenmuster abgeglichen, wenn jedes geschachtelte Muster mit dem entsprechenden Element einer Eingabesequenz übereinstimmt. Sie können ein beliebiges Muster in einem Listenmuster verwenden. Verwenden Sie zum Abgleichen eines Elements das Ausschussmuster, oder verwenden Sie, wenn Sie das Element auch erfassen möchten, das var-Muster, wie im folgenden Beispiel gezeigt:

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.

Die vorherigen Beispiele entsprechen einer ganzen Eingabesequenz mit einem Listenmuster. Um Elemente nur am Anfang oder/und am Ende einer Eingabesequenz abzugleichen, verwenden Sie wie im folgenden Beispiel gezeigt das Slicemuster ..:

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

Ein Slicemuster entspricht 0 (null) oder mehr Elementen. Sie können höchstens ein Slicemuster in einem Listenmuster verwenden. Das Slicemuster kann nur in einem Listenmuster angezeigt werden.

Sie können auch einen Teilmuster wie im folgenden Beispiel gezeigt in einem Segmentmuster verschachteln:

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

Weitere Informationen finden Sie im Hinweis zum Featurevorschlag Listenmuster.

C#-Sprachspezifikation

Weitere Informationen finden Sie im Abschnitt Muster und Musterabgleich der C#-Sprachspezifikation.

Informationen zu in C# 8 und höher eingeführten Features finden Sie in den folgenden Featurevorschlägen:

Weitere Informationen