Relationale, logische und klammerte Muster

Tip

Dieser Artikel ist Teil des Abschnitts "Grundlagen" für Entwickler, die bereits mindestens eine Programmiersprache kennen und C# erlernen. Beginnen Sie mit der Übersicht über den Musterabgleich , wenn Muster für Sie neu sind. Vollständige Sprachregeln finden Sie unter relationalen Mustern und logischen Mustern in der Sprachreferenz.

Relationale und logische Muster beschreiben Bereiche, Alternativen und Ausschlüsse. Die folgende Methode kombiniert sie, um eine Temperatur zu klassifizieren:

static string ClassifyTemperature(int temperature) =>
    temperature switch
    {
        < 0 => "Below freezing",
        >= 18 and <= 24 => "Comfortable",
        (>= 0 and < 10) or > 30 => "Far outside the comfortable range",
        _ => "Cool or warm"
    };

Der Ausdruck temperature ist die Mustereingabe. C# wertet ihn einmal aus, und jeder Schalterarm testet den resultierenden Wert. Die Arme zeigen diese Tests:

  • < 0 testet eine Grenze.
  • >= 18 and <= 24 prüft einen Bereich.
  • (>= 0 and < 10) or > 30 testet zwei alternative Bereiche.

In diesem Artikel werden sowohl Muster als auch imperative Bedingungen gezeigt, damit Sie jedes Formular erlernen und vergleichen können, wie sie dieselben Entscheidungen ausdrücken. Eine einzelne Bedingung kann in beiden Formen ähnlich aussehen. Muster können eine Reihe zusammengehöriger Verzweigungen leichter lesbar machen, indem die Optionen direkt neben den zugehörigen Ergebnissen stehen. Wählen Sie das Formular aus, mit dem der Code am einfachsten zu verstehen ist.

Vergleichen von Werten mit relationalen Mustern

Ein relationales Muster vergleicht seine Mustereingabe mit einer Konstante zur Kompilierzeit unter Verwendung von <, >, <= oder >=. Eine Kompilierungszeitkonstante ist ein Wert, den der Compiler beim Kompilieren des Programms auswerten kann. Numerische und Zeichenliterale und const Variablen kompatibler numerischer oder Zeichentypen sind repräsentative Beispiele. Normale Variablen, Eigenschaften, Methodenaufrufe und static readonly Felder sind keine Kompilierungszeitkonstanten. Im einleitenden Beispiel testen sowohl >= 18 als auch <= 24 denselben ausgewerteten Wert temperature.

Dasselbe relationale Symbol kann in einem normalen Ausdruck oder in einem Muster angezeigt werden. Im folgenden Beispiel werden beide Formen mit einer Temperatur verwendet:

static void ShowExpressionAndPattern(int temperature, int threshold)
{
    bool belowThreshold = temperature < threshold;
    bool belowFreezing = temperature is < 0;

    string description = temperature switch
    {
        < 0 => "Freezing",
        0 => "Freezing point",
        > 0 => "Above freezing"
    };

    Console.WriteLine(
        $"Below threshold: {belowThreshold}; " +
        $"below freezing: {belowFreezing}; {description}");
}

temperature < threshold ist ein relationaler Ausdruck. Es wertet beide Operanden aus und ergibt eine bool. Jeder der beiden Operanden kann ein nichtkonstanter Ausdruck sein.

In temperature is < 0, temperature ist der Mustereingabeausdruck. C# wertet sie aus, und das relationale Muster < 0 testet den resultierenden Wert. Im switch-Zweig < 0 => "Freezing" liefert der Ausdruck vor switch die Eingabe, sodass das Muster nur < 0 enthält.

Der Ausdruck kann temperature mit der Variablen threshold vergleichen. Ein relationaler Operand muss eine Kompilierungszeitkonstante sein. Verwenden Sie daher den relationalen Ausdruck, wenn der Vergleichswert eine Variable ist. Wenn der Vergleichswert konstant ist, kann eines der Beiden Formulare funktionieren.

Wenn der rechte Operand konstant ist, wählen Sie hauptsächlich nach Lesbarkeit. Ein relationaler Ausdruck passt häufig zu einem direkten Vergleich. Ein relationales Muster lässt sich mit anderen Mustern kombinieren und eignet sich besonders, wenn mehrere Bereiche Switch-Ergebnissen zugeordnet werden.

Kombinieren von Bedingungen mit logischen Mustern

Logische Muster kombinieren oder verwerfen Muster mit den Musteroperatoren and, orund not:

  • Ein and Muster stimmt überein, wenn beide geschachtelten Muster übereinstimmen.
  • Ein or Muster passt, wenn eines von beiden verschachtelten Mustern passt.
  • Ein not Muster ist erfolgreich, wenn das geschachtelte Muster fehlschlägt.

Im einleitenden Beispiel wird and verwendet, um einen Bereich zu beschreiben, und or, um Alternativen zu beschreiben. Ein not-Pattern kann einen Wert ausschließen, wie in status is not Status.Complete. Die folgenden Methoden zeigen beide Formen, damit Sie ihre Syntax erlernen und vergleichen können, wie sie denselben Test ausdrücken:

static bool IsWeekendPattern(DayOfWeek day) =>
    day is DayOfWeek.Saturday or DayOfWeek.Sunday;

static bool IsWeekendImperative(DayOfWeek day) =>
    day == DayOfWeek.Saturday || day == DayOfWeek.Sunday;

Das Formularmuster verwendet zwei konstante Muster, die durch or verbunden sind. Das imperative Formular verwendet zwei Gleichheitsausdrücke, die mit dem Operator "conditional-OR ||" verknüpft sind. Beide Formen sind für diese einzelne Bedingung prägnant und klar. Wählen Sie das Formular aus, das am besten zum umgebenden Code passt. Muster verdeutlichen häufig mehrere verwandte Auswahlmöglichkeiten in einem switch, wie im öffnenden Beispiel.

Musteroperatoren bilden Muster anstelle von Booleschen Ausdrücken: and entspricht der Musterkonjunktion, or den Musteralternativen und not der Mustennegation. Boolesche Ausdrücke verwenden &&, ||und !. Wählen Sie aus or , wann mehrere Musteralternativen dasselbe Ergebnis haben. Wählen Sie not, wenn das Ausdrücken des ausgeschlossenen Musters klarer ist, als jeden zulässigen Wert aufzulisten.

Gruppieren von Mustern mit Klammern

Ein Klammermuster verwendet Klammern, um anzuzeigen oder zu ändern, wie geschachtelte Muster gruppiert werden. Die Bindung bestimmt, welche Muster-Operanden ein Operator zusammenfasst, ähnlich einer impliziten Gruppierung, wenn Sie keine Klammern setzen. C# gibt die folgende Bindungsreihenfolge an:

  1. not
  2. and
  3. or

Der folgende Test akzeptiert Prioritäten 1 bis 3 oder die besondere Priorität 9:

static bool IsAcceptedPriority(int priority) =>
    priority is (>= 1 and <= 3) or 9;

Die Compilergruppen and vor or. Die Klammern machen die beabsichtigte Gruppierung explizit und die beiden Alternativen leicht zu erkennen: der Bereich von 1 bis 3 oder 9. Verwenden Sie der Lesbarkeit halber immer Klammern, wenn ein Muster and und or kombiniert oder wenn not auf ein zusammengesetztes Muster angewendet wird. Klammern können auch die Standardgruppierung ändern, wie in not (>= 1 and <= 3) gezeigt.

Die Reihenfolge der Laufzeitprüfungen für geschachtelte Muster ist nicht spezifiziert, und Musteroperatoren folgen den Regeln für den Musterabgleich statt Booleschen Kurzschlussregeln. Schreiben Sie geschachtelte Muster, sodass ihr Ergebnis unabhängig von der Prüfreihenfolge ist.

Verwenden eines when Schutzes für eine separate Bedingung

Logische Muster funktionieren am besten, wenn geschachtelte Muster den Eingabewert selbst beschreiben. Ein when Schutz ist eine zusätzliche boolesche Bedingung auf einer Beschriftung oder einem case Schalterarm. Verwenden Sie eine Schutzvorrichtung, wenn die Entscheidung auch von informationen abhängig ist, die von der Mustereingabe getrennt sind.

Die folgende Warnung hängt von der Temperatur und einem separaten isOutdoors Wert ab:

static string GetHeatWarning(int temperature, bool isOutdoors) =>
    temperature switch
    {
        > 35 when isOutdoors => "High heat outdoors",
        > 35 => "High heat",
        _ => "No heat warning"
    };

Das relationale Muster > 35 beschreibt die temperature Eingabe. Der Schutz when isOutdoors überprüft einen separaten Wert. Ein Guard ist auch vorzuziehen, wenn die Bedingung einen Methodenaufruf oder einen booleschen Ausdruck benötigt, der von der Mustersyntax nicht eindeutig ausgedrückt wird.

Verwenden Sie relationale und logische Muster, wenn sie die zulässigen Shapes oder Werte der Eingabe einfacher erkennen lassen, insbesondere über mehrere Schalterarme. Verwenden Sie einen normalen booleschen Ausdruck, wenn er eine direkte Bedingung einfacher angibt. Verwenden Sie eine when Schutzvorrichtung, wenn eine Schalterauswahl von einem separaten Wert oder von einer Bedingung abhängt, die besser als boolescher Ausdruck ausgedrückt wird.

Siehe auch