Freigeben über


Mustervergleich - die Ausdrücke is and switch sowie die Operatoren and, or, and not in patterns

Sie verwenden den is expression, the switch-Anweisung, and the switch expression , um einen Eingabeausdruck mit einer beliebigen Anzahl von Merkmalen abzugleichen. 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: Überprüfen Sie den Laufzeittyp eines Ausdrucks, und weisen Sie, wenn eine Übereinstimmung erfolgreich ist, einer deklarierten Variablen ein Ausdrucksergebnis zu.
  • Typmuster: Überprüfen Sie den Laufzeittyp eines Ausdrucks.
  • Konstantenmuster: Testen, dass ein Ausdrucksergebnis einer angegebenen Konstante entspricht.
  • Relationale Muster: Vergleichen eines Ausdrucksergebnisses mit einer angegebenen Konstante.
  • Logische Muster: Testen, dass ein Ausdruck einer logischen Kombination von Mustern entspricht.
  • Eigenschaftsmuster: Testen, ob die Eigenschaften oder Felder eines Ausdrucks mit verschachtelten Mustern übereinstimmen.
  • Positionelles Muster: Dekonstruieren Sie ein Ausdrucksergebnis und testen Sie, ob die resultierenden Werte verschachtelten Mustern entsprechen.
  • var Muster: Vergleichen Sie einen beliebigen Ausdruck und weisen Sie dessen Ergebnis einer deklarierten Variablen zu.
  • Verwerfungsmuster: Übereinstimmung mit einem beliebigen Ausdruck.
  • Listenmuster: Testen Sie, dass eine Abfolge von Elementen den entsprechenden geschachtelten Mustern entspricht.

Logical, Eigenschaft, positional, and list patterns are recursive patterns. 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 diese Variable dem konvertierten 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 hat eine Identitätskonvertierung nach T.
  • Der Typ T ist ein ref struct Typ, und es gibt eine Identitätskonvertierung vom Ausdruck in 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. Dies umfasst Vererbungsbeziehungen und Schnittstellenimplementierungen. 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 Wert mit dem zugrunde liegenden Typ T und Nullable<T>.HasValue ist true.
  • A boxing or unboxing Konvertierung existiert vom Laufzeittyp eines Ausdrucksergebnisses zum Typ T , wenn der Ausdruck keine Instanz eines ref struct.

Deklarationsmuster berücksichtigen keine benutzerdefinierten Konvertierungen oder implizite Span-Konvertierungen.

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 stimmt ein Typmuster mit einem Ausdruck überein, wenn ein Ausdrucksergebnis nicht null ist und sein Laufzeittyp eine der oben genannten Bedingungen erfüllt.

Authentifizierung mit einem angegebenen Token. negatednullconstant pattern, as the following example shows:

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

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

Konstantenmuster

Das Konstantenmuster ist eine alternative Syntax, wenn == der rechte Operand eine Konstante ist. 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> mit Konstantenzeichenfolgen übereinstimmt oder ReadOnlySpan<char> 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 negatednull Konstantenmuster verwenden, um auf Nicht-Null zu prüfen, wie das folgende Beispiel zeigt:

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<, >, <=, or >=. 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:

  • Negationnot , das mit einem Ausdruck übereinstimmt, wenn das negierte Muster nicht mit dem Ausdruck übereinstimmt. Das folgende Beispiel zeigt, wie Sie ein constantnull Muster negieren können, um zu prüfen, ob ein Ausdruck nicht null ist:

    if (input is not null)
    {
        // ...
    }
    
  • Conjunctiveand Muster, das auf einen Ausdruck passt, wenn beide Muster auf den Ausdruck passen. 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",
    };
    
  • Disjunctiveor Muster, das auf einen Ausdruck passt, wenn eines der beiden Muster auf den Ausdruck passt, wie das folgende Beispiel zeigt:

    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 sind auf der Grundlage der Bindungsreihenfolge der Ausdrücke wie folgt angeordnet:

  • not
  • and
  • or

The not -Muster bindet sich zuerst an seinen Operanden. The and -Muster bindet sich nach jedem not -Musterausdruck. The or -Muster wird gebunden, nachdem alle not and and -Muster an Operanden gebunden sind. Das folgende Beispiel versucht, alle Zeichen zu finden, die keine Kleinbuchstaben sind, a - z. Es liegt ein Fehler vor, denn die not -Muster vor dem and pattern:

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

Die Standardbindung bedeutet, dass das vorherige Beispiel als das folgende Beispiel geparst 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 den Fehler zu beheben, müssen Sie angeben, dass das not -Muster an den >= 'a' and <= 'z' expression:

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

Das Hinzufügen von Klammern wird umso wichtiger, je komplizierter Ihre Muster 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 der gleichen Bindungsreihenfolge geprüft werden, ist nicht definiert. Zur Laufzeit werden die rechten, verschachtelten Muster aus mehreren or Muster und mehrere and Muster können zunächst geprü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."),
};

Dieses Konstrukt bedeutet insbesondere, dass das leere Eigenschaftsmuster is { } mit allen Nicht-Null-Elementen übereinstimmt und anstelle der is not null zum Erstellen einer Variablen verwendet werden kann: somethingPossiblyNull is { } somethingDefinitelyNotNull

if (GetSomeNullableStringValue() is { } nonNullValue) // Empty property pattern with variable creation
{
    Console.WriteLine("NotNull:" + nonNullValue);
}
else
{
    nonNullValue = "NullFallback"; // we can access the variable here.
    Console.WriteLine("it was null, here's the fallback: " + nonNullValue);
}

Ein Eigenschaftsmuster ist ein rekursives Muster. Sie können ein beliebiges Muster als 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 orMusterkombinator und Datensatztypen verwendet.

Sie können 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. Der für das Positionsmuster generierte Code ruft die Deconstruct Methode auf.

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 vorangegangenen Beispiel ist das Muster var (x, y) gleich 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 Verwerfungsmuster_ , um einen beliebigen Ausdruck zu finden, einschließlich null, wie folgendes Beispiel zeigt:

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

Sie können ein Array oder eine Liste mit einer Abfolge von Mustern abgleichen, wie das folgende Beispiel zeigt:

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 das vorangehende Beispiel zeigt, wird ein Listenmuster übereinstimmend, wenn jedes verschachtelte 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 zu finden, verwenden Sie das slice pattern.., as the following example shows:

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