Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
11.1 Allgemein
Ein Muster ist eine syntaktische Form, die mit dem is Operator (§12.15.12) in einem switch_statement (§13.8.3) und in einem switch_expression (§12.12) verwendet werden kann, um die Form der Daten auszudrücken, mit denen eingehende Daten verglichen werden sollen. Muster können rekursiv sein, sodass Teile der Daten mit Untermustern abgeglichen werden können.
Ein Muster wird anhand eines Werts in einer Reihe von Kontexten getestet:
- In einer Switch-Anweisung wird das Muster einer Fallbezeichnung anhand des Ausdrucks der Switch-Anweisung getestet.
- Bei einem Is-Pattern-Operator wird das Muster auf der rechten Seite mit dem Ausdruck auf der linken Seite getestet.
- In einem Schalterausdruck wird das Muster eines switch_expression_arm auf der linken Seite des Schalterausdrucks anhand des Ausdrucks getestet.
- In geschachtelten Kontexten wird das Untermuster abhängig vom Musterformular anhand von Werten getestet, die aus Eigenschaften, Feldern oder aus anderen Eingabewerten indiziert wurden.
Der Wert, für den ein Muster getestet wird, wird als Mustereingabewert bezeichnet.
11.2 Musterformulare
11.2.1 Allgemein
Ein Muster kann eine der folgenden Formen aufweisen:
pattern
: logical_pattern
;
primary_pattern
: parenthesized_pattern
| declaration_pattern
| constant_pattern
| var_pattern
| positional_pattern
| property_pattern
| discard_pattern
| type_pattern
| relational_pattern
;
parenthesized_pattern
: '(' pattern ')'
;
Die '(' pattern ')' Produktion ermöglicht es, ein Muster in Klammern einzuschließen, um die Reihenfolge der Auswertung zwischen Mustern unter Verwendung eines der logical_patterns zu erzwingen.
Einige Musterkönnen zur Deklaration einer lokalen Variablen führen.
Jedes Musterformular definiert den Satz von Typen für Eingabewerte, auf die das Muster angewendet werden kann. Ein Muster P gilt für einen Typ T , wenn T es sich um die Typen handelt, deren Werte das Muster möglicherweise abgleichen kann. Es handelt sich um einen Kompilierungsfehler, wenn ein Muster P in einem Programm angezeigt wird, um einem Mustereingabewert (§11.1) des Typs T zu entsprechen, falls P nicht zutreffend T.
Beispiel: Im folgenden Beispiel wird ein Kompilierungszeitfehler generiert, da der Kompilierungszeittyp
vlautetTextReader. Eine Variable vom TypTextReaderkann niemals einen Wert aufweisen, der referenzkompatibel ist mitstring:TextReader v = Console.In; // compile-time type of 'v' is 'TextReader' if (v is string) // compile-time error { // code assuming v is a string }Im Folgenden wird jedoch kein Kompilierungszeitfehler generiert, da der Kompilierungszeittyp
vlautetobject. Eine Variable des Typsobjectkönnte einen Wert aufweisen, der referenzkompatibel ist mitstring:object v = Console.In; if (v is string s) { // code assuming v is a string }Endbeispiel
Jedes Musterformular definiert den Wertesatz, für den das Muster dem Wert zur Laufzeit entspricht .
Die Reihenfolge der Auswertung von Vorgängen und Nebenwirkungen während des Musterabgleichs (Aufrufe Deconstruct, Eigenschaftenzugriffe und Aufrufe von Methoden in System.ITuple) wird nicht angegeben.
11.2.2 Deklarationsmuster
Ein declaration_pattern wird verwendet, um zu testen, ob ein Wert einen bestimmten Typ aufweist, und wenn der Test erfolgreich ist, um optional den Wert in einer Variablen dieses Typs bereitzustellen.
declaration_pattern
: type simple_designation
;
simple_designation
: discard_designation
| single_variable_designation
;
discard_designation
: '_'
;
single_variable_designation
: identifier
;
Ein simple_designation mit dem Token _ gilt als discard_designation und nicht als single_variable_designation.
Der Laufzeittyp des Werts wird anhand der gleichen Regeln getestet, die im Is-Type-Operator (§12.15.12.12.1) angegeben sind. Wenn der Test erfolgreich ist, entspricht das Muster diesem Wert. Es handelt sich um einen Kompilierungszeitfehler, wenn der Typ ein Nullwerttyp (§8.3.12) oder ein nullabler Bezugstyp (§8.9.3) ist. Dieses Musterformular entspricht niemals einem null Wert.
Hinweis: Der Is-Type-Ausdruck
e is Tund das Deklarationsmustere is T _sind gleichwertig, wennTes sich nicht um einen Null-Typ handelt. Endnote
Bei einem Mustereingabewert (§11.1) e wird, wenn die simple_designationdiscard_designation ist, ein Verwerfen (§9.2.9.2) bezeichnet, und der Wert von e ist an nichts gebunden. (Obwohl eine deklarierte Variable mit dem Namen _ zu diesem Zeitpunkt im Bereich enthalten sein kann, wird diese benannte Variable in diesem Kontext nicht angezeigt.) Andernfalls wird eine lokale Variable (§9.2.9) des angegebenen Typs eingeführt, wenn der simple_designationsingle_variable_designation ist. Diese lokale Variable wird dem Wert des Mustereingabewerts zugewiesen, wenn das Muster dem Wert entspricht .
Bestimmte Kombinationen des statischen Typs des Mustereingabewerts und des angegebenen Typs werden als inkompatibel betrachtet und führen zu einem Kompilierungszeitfehler. Ein Wert des statischen Typs E wird als Muster angegeben , das mit dem Typ T kompatibel ist, wenn eine Identitätskonvertierung, eine implizite oder explizite Verweiskonvertierung, eine Boxkonvertierung, eine Unboxing-Konvertierung oder eine implizite oder explizite Nullwertetypkonvertierung von E zu T, oder wenn ET es sich um einen offenen Typ (§8.4.3) handelt. Ein Deklarationsmuster, das einen Typ T benennt, gilt für jeden Typ E , für den E das Muster kompatibel ist T.
Hinweis: Die Unterstützung für offene Typen kann am nützlichsten sein, wenn Typen überprüft werden, die entweder Struktur- oder Klassentypen sein können, und boxen ist zu vermeiden. Endnote
Beispiel: Das Deklarationsmuster ist nützlich, um Laufzeittypentests von Referenztypen durchzuführen und das Idiom zu ersetzen.
var v = expr as Type; if (v != null) { /* code using v */ }mit der etwas prägnanteren
if (expr is Type v) { /* code using v */ }Endbeispiel
Beispiel: Das Deklarationsmuster kann verwendet werden, um Werte von nullablen Typen zu testen: Ein Wert vom Typ
Nullable<T>(oder ein BoxedT) entspricht einem TypmusterT2 id, wenn der Wert ungleich NULL ist undT2Toder ein Basistyp oder eine Schnittstelle vonT. Beispiel: im Codefragmentint? x = 3; if (x is int v) { /* code using v */ }Die Bedingung der
ifAnweisung befindettruesich zur Laufzeit, und die Variableventhält den Wert3des Typsintinnerhalb des Blocks. Nach dem Block befindet sich die Variablevim Bereich, aber nicht definitiv zugewiesen. Endbeispiel
11.2.3 Konstantenmuster
Ein constant_pattern wird verwendet, um den Wert eines Mustereingabewerts (§11.1) anhand des angegebenen Konstantenwerts zu testen.
constant_pattern
: constant_expression
;
Ein Konstantenmuster P gilt für einen Typ T , wenn eine implizite Konvertierung vom konstanten Ausdruck in P den Typ Tvorhanden ist.
Bei einem Konstantenmuster Pist der konvertierte Wert
- wenn der Typ des Mustereingabewerts ein integraler Typ oder ein Enumerationstyp ist, wird der Konstantenwert des Musters in diesen Typ konvertiert; sonst
- wenn der Typ des Mustereingabewerts die NULL-Version eines integralen Typs oder eines Enumerationstyps ist, wird der konstanten Wert des Musters in den zugrunde liegenden Typ konvertiert; sonst
- der Wert des Konstantenwerts des Musters.
Bei einem Mustereingabewert e und einem konstanten Muster P mit konvertiertem Wert v
- wenn e einen integralen Typ oder Enumerationstyp hat oder eine nullable Form eines dieser Typen aufweist und v einen integralen Typ aufweist, entspricht
Pdem Wert e, wenn das Ergebnis des Ausdruckse == vlautettrue; andernfalls - das Muster
Pentspricht dem Wert e , wennobject.Equals(e, v)zurückgegeben wirdtrue.
Beispiel: Die
switchAnweisung in der folgenden Methode verwendet fünf Konstantenmuster in ihren Fallbeschriftungen.static decimal GetGroupTicketPrice(int visitorCount) { switch (visitorCount) { case 1: return 12.0m; case 2: return 20.0m; case 3: return 27.0m; case 4: return 32.0m; case 0: return 0.0m; default: throw new ArgumentException(...); } }Endbeispiel
11.2.4 Var-Muster
Ein var_patternentspricht jedem Wert. Das heißt, ein Musterabgleichsvorgang mit einem var_pattern ist immer erfolgreich.
Ein var_pattern gilt für jeden Typ.
var_pattern
: 'var' designation
;
designation
: simple_designation
| tuple_designation
;
tuple_designation
: '(' designations? ')'
;
designations
: designation (',' designation)*
;
Bei einem Mustereingabewert (§11.1) e, wenn die Bezeichnungdiscard_designation ist, wird ein Verwerfen (§9.2.9.2) bezeichnet, und der Wert von e ist an nichts gebunden. (Obwohl eine deklarierte Variable mit diesem Namen zu diesem Zeitpunkt im Bereich enthalten sein kann, wird diese benannte Variable in diesem Kontext nicht angezeigt.) Andernfalls ist die Bezeichnungsingle_variable_designation, zur Laufzeit ist der Wert von e an eine neu eingeführte lokale Variable (§9.2.9) dieses Namens gebunden, deren Typ der statische Typ von e ist, und der Mustereingabewert dieser lokalen Variablen zugewiesen wird.
Es ist ein Fehler, wenn der Name var an einen Typ gebunden würde, in dem ein var_pattern verwendet wird.
Wenn die Bezeichnung eine tuple_designation ist, entspricht das Muster einem positional_pattern (§11.2.5) der (var, ...
) sind die Bezeichnungeninnerhalb der tuple_designation. Das Muster var (x, (y, z)) entspricht (var x, (var y, var z))z. B. .
11.2.5 Positionsmuster
Ein positional_pattern überprüft, ob der Eingabewert nicht nullist, ruft eine geeignete Deconstruct Methode (§12.7) auf und führt einen weiteren Musterabgleich für die resultierenden Werte durch. Es unterstützt auch eine Tupel-ähnliche Mustersyntax (ohne den Typ, der bereitgestellt wird), wenn der Typ des Eingabewerts mit dem Typ übereinstimmt, der den Typ des Eingabewerts enthältDeconstruct, oder wenn der Typ des Eingabewerts ein Tupeltyp ist oder ob der Typ des Eingabewerts oder object der Laufzeittyp des Ausdrucks System.ITupleimplementiert wirdSystem.ITuple.
positional_pattern
: type? '(' subpatterns? ')' property_subpattern? simple_designation?
;
subpatterns
: subpattern (',' subpattern)*
;
subpattern
: pattern
| identifier ':' pattern
;
Wenn eine Übereinstimmung eines Eingabewerts mit denUnterpattern des () übereinstimmt, wird eine Methode ausgewählt, indem sie im Typ nach barrierefreien Deklarationen Deconstruct suchen und eine davon auswählen, die dieselben Regeln wie für die Dekonstruktionsdeklaration verwendet.
Es ist ein Fehler, wenn ein positional_pattern den Typ ausgelassen, einen einzelnen Unterpattern ohne Bezeichner hat, keine property_subpattern hat und keine simple_designation hat. Dies unterscheidet sich zwischen einer constant_pattern , die Klammer und eine positional_pattern ist.
Um die Werte zu extrahieren, die mit den Mustern in der Liste übereinstimmen sollen,
- Wenn der Typ ausgelassen wird und der Typ des Eingabeausdrucks ein Tupeltyp ist, muss die Anzahl der Unterpattern mit der Kardinalität des Tupels identisch sein. Jedes Tupelelement wird mit dem entsprechenden Unterpattern abgeglichen, und die Übereinstimmung ist erfolgreich, wenn alle diese Elemente erfolgreich sind. Wenn ein Unterpattern über einen Bezeichner verfügt, muss dieser ein Tupelelement an der entsprechenden Position im Tupeltyp benennen.
- Andernfalls handelt es sich bei einem geeigneten
DeconstructElement des Typs um einen Kompilierungszeitfehler, wenn der Typ des Eingabewerts nicht musterkompatibel mit dem Typ ist. Zur Laufzeit wird der Eingabewert anhand des Typs getestet. Wenn dies fehlschlägt, schlägt die Positionsmustervergleich fehl. Wenn er erfolgreich ist, wird der Eingabewert in diesen Typ konvertiert undDeconstructmit neu generierten Variablen aufgerufen, um die Ausgabeparameter zu empfangen. Jeder empfangene Wert wird mit dem entsprechenden Unterpattern abgeglichen, und die Übereinstimmung ist erfolgreich, wenn alle diese erfolgreich sind. Wenn ein Unterpattern über einen Bezeichner verfügt, muss dieser einen Parameter an der entsprechenden Position vonDeconstruct. - Andernfalls wird kein Typ angegeben, und der Eingabewert ist vom Typ
objectoder einem Typ, der von einer impliziten Verweiskonvertierung in konvertiertSystem.ITuplewerden kann, und kein Bezeichner unter den Unterpattern angezeigt wird, wird die Übereinstimmung verwendetSystem.ITuple. - Andernfalls ist das Muster ein Kompilierungszeitfehler.
Die Reihenfolge, in der Unterpattern zur Laufzeit abgeglichen werden, ist nicht angegeben, und eine fehlgeschlagene Übereinstimmung versucht möglicherweise nicht, alle Unterpattern abzugleichen.
Beispiel: Hier deconieren wir ein Ausdrucksergebnis und stimmen mit den resultierenden Werten mit den entsprechenden geschachtelten Mustern überein:
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", }; 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); }Endbeispiel
Beispiel: Die Namen von Tupelelementen und Deconstruct-Parametern können wie folgt in einem Positionsmuster verwendet werden:
var numbers = new List<int> { 10, 20, 30 }; if (SumAndCount(numbers) is (Sum: var sum, Count: var count)) { Console.WriteLine($"Sum of [{string.Join(" ", numbers)}] is {sum}"); } 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); }Die erzeugte Ausgabe ist
Sum of [10 20 30] is 60Endbeispiel
11.2.6 Eigenschaftenmuster
Ein property_pattern überprüft, ob der Eingabewert nicht nullist, und stimmt rekursiv mit Werten überein, die durch die Verwendung von barrierefreien Eigenschaften oder Feldern extrahiert wurden.
property_pattern
: type? property_subpattern simple_designation?
;
property_subpattern
: '{' '}'
| '{' subpatterns ','? '}'
;
Es ist ein Fehler, wenn ein Unterpattern eines property_pattern keinen Bezeichner enthält.
Es handelt sich um einen Kompilierungszeitfehler, wenn der Typ ein Nullwerttyp (§8.3.12) oder ein nullabler Bezugstyp (§8.9.3) ist.
Hinweis: Ein Nullüberprüfungsmuster fällt aus einem trivialen Eigenschaftsmuster heraus. Um zu überprüfen, ob die Zeichenfolge
sungleich NULL ist, kann eine der folgenden Formulare geschrieben werden:#nullable enable string s = "abc"; if (s is object o) ... // o is of type object if (s is string x1) ... // x1 is of type string if (s is {} x2) ... // x2 is of type string if (s is {}) ...Endnote
Wenn eine Übereinstimmung eines Ausdrucks e mit denUnterpattern des {} übereinstimmt, handelt es sich um einen Kompilierungszeitfehler, wenn der Ausdruck e nicht musterkompatibel mit dem typ T ist, der nach Typ bestimmt ist. Wenn der Typ nicht vorhanden ist, wird der Typ als statischer Typ von e angenommen. Jeder der Bezeichner, die auf der linken Seite seiner Unterpattern angezeigt werden, muss eine lesbare Eigenschaft oder ein lesbares Feld von T festlegen. Wenn die simple_designation des property_pattern vorhanden ist, deklariert sie eine Mustervariable vom Typ T.
Zur Laufzeit wird der Ausdruck auf T getestet. Wenn dies fehlschlägt, schlägt die Übereinstimmung des Eigenschaftenmusters fehl, und das Ergebnis lautet false. Wenn dies erfolgreich ist, wird jedes property_subpattern Feld oder jede Eigenschaft gelesen und ihr Wert mit dem entsprechenden Muster abgeglichen. Das Ergebnis der gesamten Übereinstimmung ist false nur, wenn das Ergebnis einer dieser Übereinstimmungen lautet false. Die Reihenfolge, in der Unterpattern abgeglichen werden, wird nicht angegeben, und eine fehlgeschlagene Übereinstimmung testet möglicherweise nicht alle Unterpattern zur Laufzeit. Wenn die Übereinstimmung erfolgreich ist und die simple_designation der property_pattern ein single_variable_designation ist, wird der deklarierte Wert zugewiesen.
Die property_pattern können verwendet werden, um eine Mustervergleichung mit anonymen Typen zu erzielen.
Beispiel:
var o = ...; if (o is string { Length: 5 } s) ...Endbeispiel
Beispiel: Eine Laufzeittypüberprüfung und eine Variabledeklaration können einem Eigenschaftenmuster wie folgt hinzugefügt werden:
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."), };Die erzeugte Ausgabe ist
Hello Hi! 12345 abcEndbeispiel
11.2.7 Muster verwerfen
Jeder Ausdruck stimmt mit dem Verwerfenmuster überein, was zu dem Wert des Ausdrucks führt, der verworfen wird.
discard_pattern
: '_'
;
Es handelt sich um einen Kompilierungsfehler, um ein Verwerfenmuster in einem relational_expression des Formulars relational_expressionisMusters oder als Muster einer switch_label zu verwenden.
Hinweis: Verwenden Sie in diesen Fällen eine var_pattern mit einem Verwerfen
var _, um einem beliebigen Ausdruck zu entsprechen. Endnote
Beispiel:
Console.WriteLine(GetDiscountInPercent(DayOfWeek.Friday)); Console.WriteLine(GetDiscountInPercent(null)); Console.WriteLine(GetDiscountInPercent((DayOfWeek)10)); 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, };Die erzeugte Ausgabe ist
5.0 0.0 0.0Hier wird ein Verwerfenmuster verwendet, um einen ganzzahligen Wert zu behandeln
null, der nicht über das entsprechende Element derDayOfWeekEnumeration verfügt. Dadurch wird sichergestellt, dass derswitchAusdruck alle möglichen Eingabewerte verarbeitet. Endbeispiel
11.2.8 Typmuster
Ein type_pattern wird verwendet, um zu testen, dass der Mustereingabewert (§11.1) einen bestimmten Typ aufweist.
type_pattern
: type
;
Ein Typmuster, das einen Typ T benennt, gilt für jeden Typ E , für den Edas Muster kompatibelT ist (§11.2.2).
Der Laufzeittyp des Werts wird anhand der im Is-Type-Operator angegebenen Regeln (§12.15.12.12.1) getestet. Wenn der Test erfolgreich ist, entspricht das Muster diesem Wert. Es handelt sich um einen Kompilierungszeitfehler, wenn der Typ ein nullwertbarer Typ ist. Dieses Musterformular entspricht niemals einem null Wert.
11.2.9 Relationales Muster
Ein relational_pattern wird verwendet, um den Mustereingabewert (§11.1) relational anhand eines Konstantenwerts zu testen.
relational_pattern
: '<' relational_expression
| '<=' relational_expression
| '>' relational_expression
| '>=' relational_expression
;
Die relational_expression in einem relational_pattern ist erforderlich, um einen konstanten Wert auszuwerten.
Relationale Muster unterstützen die relationalen Operatoren , , , und >= auf allen integrierten Typen, die solche binären relationalen Operatoren mit beiden Operanden mit demselben Typ unterstützen: sbyte, intushortbyteshort, uint, longulongchardecimaldoublefloat, nint, und nuintEnums. ><=<
Eine relational_patterngilt für einen Typ T , wenn ein geeigneter integrierter binärer relationaler Operator mit beiden Operanden des Typs Tdefiniert ist, oder wenn eine explizite nullable oder unboxing Konvertierung vom T Typ des Konstantenausdrucks vorhanden ist.
Es handelt sich um einen Kompilierungsfehler, wenn der Ausdruck als double.NaN, float.NaNoder eine NULL-Konstante ausgewertet wird.
Wenn der Eingabewert einen Typ aufweist, für den ein geeigneter integrierter binärer relationaler Operator definiert ist, wird die Auswertung dieses Operators als Bedeutung des relationalen Musters verwendet. Andernfalls wird der Eingabewert mithilfe einer expliziten NULL-Konvertierung oder Unboxing-Konvertierung in den Typ des Konstantenausdrucks konvertiert. Es handelt sich um einen Kompilierzeitfehler, wenn es keine solche Konvertierung gibt. Das Muster wird als nicht übereinstimmend betrachtet, wenn die Konvertierung fehlschlägt. Wenn die Konvertierung erfolgreich ist, ist das Ergebnis des Musterabgleichsvorgangs das Ergebnis der Auswertung des Ausdrucks e «op» v , bei dem e es sich um die konvertierte Eingabe handelt, «op» ist der relationale Operator und v ist der konstante Ausdruck.
Beispiel:
Console.WriteLine(Classify(13)); Console.WriteLine(Classify(double.NaN)); Console.WriteLine(Classify(2.4)); static string Classify(double measurement) => measurement switch { < -4.0 => "Too low", > 10.0 => "Too high", double.NaN => "Unknown", _ => "Acceptable", };Die erzeugte Ausgabe ist
Too high Unknown AcceptableEndbeispiel
11.2.10 Logisches Muster
Ein logical_pattern wird verwendet, um das Ergebnis einer Musterabgleichung zu verwerfen oder die Ergebnisse mehrerer Mustervergleiche mithilfe von Konjunktion (and) oder Disjunktion (or) zu kombinieren.
logical_pattern
: disjunctive_pattern
;
disjunctive_pattern
: disjunctive_pattern 'or' conjunctive_pattern
| conjunctive_pattern
;
conjunctive_pattern
: conjunctive_pattern 'and' negated_pattern
| negated_pattern
;
negated_pattern
: 'not' negated_pattern
| primary_pattern
;
not, andund or werden gemeinsam als Musteroperatoren bezeichnet.
Ein negated_pattern stimmt überein, wenn das negierte Muster nicht übereinstimmt und umgekehrt. Für eine conjunctive_pattern müssen beide Muster übereinstimmen. Ein disjunctive_pattern erfordert eine Übereinstimmung mit beiden Mustern. Im Gegensatz zu ihren Sprachoperator-Gegenstücken && und ||, and und or es handelt sich nicht um Kurzschlussoperatoren.
Es handelt sich um einen Kompilierungszeitfehler für eine Mustervariable, die unter einem oder or einem not Musteroperator deklariert werden soll.
Hinweis: Da weder
notoreine bestimmte Zuordnung für eine Mustervariable erzeugt werden kann, ist es ein Fehler, einen in diesen Positionen zu deklarieren. Endnote
In einem conjunctive_pattern wird der Eingabetyp des zweiten Musters durch die Typeninschränkungsanforderungen des ersten Musters der and. Der schmale Typ eines Musters P wird wie folgt definiert:
- Wenn
Pes sich um ein Typmuster handelt, ist der schmale Typ der Typ des Typs musters. - Andernfalls ist der schmale Typ der Typ des Deklarationsmusters, wenn
Pes sich um ein Deklarationsmuster handelt. - Wenn es sich um ein rekursives Muster handelt, das einen expliziten Typ angibt, ist der schmale Typ dieser Typ.
P - Andernfalls ist der schmale Typ, wenn
Per über die Regeln fürITupleeine positional_pattern (§11.2.5) abgeglichen wirdSystem.ITuple. - Andernfalls ist die Konstante ein Konstantenmuster,
Pbei dem die Konstante nicht die Nullkonstante ist und wenn der Ausdruck keine Konstantekonvertierung in den Eingabetyp aufweist, ist der schmale Typ der Konstante. - Andernfalls ist ein relationales Muster,
Pbei dem der Konstantenausdruck keine Konstantenausdruckkonvertierung in den Eingabetyp aufweist, ist der schmale Typ der Konstante. -
PAndernfalls istorder schmale Typ der schmalen Art der Unterpattern üblich, wenn ein solcher allgemeiner Typ vorhanden ist. Zu diesem Zweck berücksichtigt der allgemeine Typalgorithmus nur Identitäts-, Box- und implizite Verweiskonvertierungen und berücksichtigt alle Unterpattern einer Abfolge vonorMustern (ignoriert Klammermuster). -
PAndernfalls ist bei einemandMuster der schmale Typ der schmale Typ des richtigen Musters. Darüber hinaus ist der schmale Typ des linken Musters der Eingabetyp des rechten Musters. - Andernfalls ist
Pder schmale Typ desPEingabetyps.
Hinweis: Wie durch die Grammatik angegeben,
nothat Vorrangandvor , was Vorrangorhat. Dies kann mithilfe von Klammern explizit angegeben oder außer Kraft gesetzt werden. Endnote
Wenn ein Muster auf der rechten Seite des isMusters angezeigt wird, wird der Umfang des Musters durch die Grammatik bestimmt. Daher werden die Musteroperatoren and, orund not innerhalb des Musters enger als die logischen Operatoren &&, ||und ! außerhalb des Musters gebunden.
Beispiel:
Console.WriteLine(Classify(13)); Console.WriteLine(Classify(-100)); Console.WriteLine(Classify(5.7)); 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", };Die erzeugte Ausgabe ist
High Too low AcceptableEndbeispiel
Beispiel:
Console.WriteLine(GetCalendarSeason(new DateTime(2021, 1, 19))); Console.WriteLine(GetCalendarSeason(new DateTime(2021, 10, 9))); Console.WriteLine(GetCalendarSeason(new DateTime(2021, 5, 11))); 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}."), };Die erzeugte Ausgabe ist
winter autumn springEndbeispiel
Beispiel:
object msg = "msg"; object obj = 5; bool flag = true; // This is parsed as: (msg is (not int) or string) result = msg is not int or string; Console.WriteLine($"msg (\"msg\"): msg is not int or string: {result}"); // This is parsed as: (obj is (int or string)) && flag bool result = obj is int or string && flag; Console.WriteLine($"obj (5), flag (true): obj is int or string && flag: {result}"); // This is parsed as: (obj is int) || ((obj is string) && flag) result = obj is int || obj is string && flag; Console.WriteLine($"obj (5), flag (true): obj is int || obj is string && flag: {result}"); flag = false; // This is parsed as: (obj is (int or string)) && flag result = obj is int or string && flag; Console.WriteLine($"obj (5), flag (false): obj is int or string && flag: {result}"); // This is parsed as: (obj is int) || ((obj is string) && flag) result = obj is int || obj is string && flag; Console.WriteLine($"obj (5), flag (false): obj is int || obj is string && flag: {result}");Die erzeugte Ausgabe ist
msg ("msg"): msg is not int or string: True obj (5), flag (true): obj is int or string && flag: True obj (5), flag (true): obj is int || obj is string && flag: True obj (5), flag (false): obj is int or string && flag: False obj (5), flag (false): obj is int || obj is string && flag: TrueEndbeispiel
11.3 Musterunternahme
Bei einer Switch-Anweisung handelt es sich um einen Fehler, wenn das Muster eines Falls von der vorherigen Gruppe nicht überwachter Fälle (§13.8.3) subsumiert wird. Informell bedeutet dies, dass jeder Eingabewert mit einem der vorherigen Fälle abgeglichen worden wäre. Die folgenden Regeln definieren, wann eine Reihe von Mustern ein bestimmtes Muster subsumiert:
Ein Muster Pentspricht einer Konstante K , wenn eine der folgenden Bedingungen enthalten ist:
- Die Spezifikation für das Laufzeitverhalten dieses Musters entspricht dem
P.K -
Pist eine type_pattern für typTundKnichtnullund der LaufzeittypKistToder ein Typ, der vonToder einem Typ abgeleitet ist, der implementiertTwird. -
Pist eine relational_pattern mit Operator «op» und konstantv, und der AusdruckK«op»vwürde ausgewertet.true -
Pist eine negated_patternnot P₁undP₁würde nicht übereinstimmenK. -
Pist eine conjunctive_patternP₁ and P₂, und beideP₁würden übereinstimmenKundP₂übereinstimmenK. -
Pist eine disjunctive_patternP₁ or P₂und würde entwederP₁übereinstimmenKoderP₂übereinstimmenK. -
Pist ein discard_pattern.
Eine Reihe von Mustern Qsubsumiert ein Muster P , wenn eine der folgenden Bedingungen enthalten ist:
-
Pist ein konstantes Muster, und jedes der Muster in der GruppeQwürde mit dem konvertierten Wert übereinstimmenP. -
Pist ein Var-Muster, und der Satz von MusternQist erschöpfend (§11.4) für den Typ des Mustereingabewerts (§11.1), und entweder ist der Mustereingabewert kein nullabler Typ oder ein MusterQin übereinstimmungen.null -
Pist ein Deklarationsmuster mit TypTund der Satz von MusternQist (T). -
Pist eine type_pattern für typT, und der Satz von MusternQist für den TypTerschöpfend. -
Pist eine relational_pattern mit Operator «op» und konstantem Wertv, und für jeden Wert des Eingabetyps, der die Beziehung «op»verfüllt, würde ein Muster in der MengeQdiesem Wert entsprechen. -
Pist eine disjunctive_patternP₁ or P₂und die Gruppe von MusternQsubsumesP₁undQSubsumesP₂. -
Pist eine conjunctive_patternP₁ and P₂und mindestens eine der folgenden Haltebereiche:QSubsumesP₁oderQSubsumenP₂. -
Pist ein negated_patternnot P₁undQist erschöpfend für den Eingabetyp, der nur die Werte berücksichtigt, die nicht übereinstimmen.P₁ -
Pist eine discard_pattern und der Satz von MusternQist für den Typ des Mustereingabewerts erschöpfend , und entweder ist der Mustereingabewert kein nullabler Typ oder ein Muster inQübereinstimmungennull. - Bei einigen Mustern handelt es sich um
Qeine disjunctive_patternQ₁ or Q₂und das Ersetzen dieses Musters durchQ₁Qin einen Satz würde einen Satz ergeben, der subsumiertPoder durchQ₂ersetzt wird, einen Satz dieser UntersummenP. - Bei einigen Mustern handelt es sich um
Qeine negated_patternnot Q₁undPwürde keinem Wert entsprechen, derQ₁übereinstimmen würde.
11.4 Mustererschöpfend
Informell ist eine Reihe von Mustern für einen Typ erschöpfend, wenn für jeden möglichen Wert dieses Typs außer NULL ein bestimmtes Muster in der Menge anwendbar ist. Die folgenden Regeln definieren, wann eine Reihe von Mustern für einen Typ erschöpfend ist:
Eine Reihe von Mustern Q ist für einen Typ erschöpfendT:
-
Tist ein integraler oder enumerationstyp oder eine nullable Version einer dieser Typen, und für jeden möglichen Wert desTnicht nullablen zugrunde liegenden Typs würde ein MusterQmit diesem Wert übereinstimmen; oder - Bei einigen Mustern handelt es sich um
Qein Var-Muster; oder - Bei einigen Mustern
Qhandelt es sich um ein Deklarationsmuster für den TypD, und es gibt eine Identitätskonvertierung, eine implizite Verweiskonvertierung oder eine Boxumwandlung vonTzuD; oder - Bei einigen Mustern
Qhandelt es sich um eine type_pattern für den TypD, und es gibt eine Identitätskonvertierung, eine implizite Verweiskonvertierung oder eine Boxumwandlung vonTzuD; oder - Bei einigen Mustern handelt es sich um
Qeine discard_pattern; oder - Die Muster
Qenthalten eine Kombination aus relational_patterns und constant_patterns, deren Bereiche zusammen jeden möglichen Wert desTnicht nullablen zugrunde liegenden Typs abdecken. FürfloatunddoubleTypen umfasstSystem.Double.NaNdies bzwSystem.Single.NaN. dies, daNaNnicht mit einem relationalen Muster abgeglichen wird; - Bei einigen Mustern handelt es sich um
Qeine disjunctive_patternP₁ or P₂und das Ersetzen dieses Musters durch sowohl alsP₂auchP₁durch einenQSatz, der erschöpfend istT; oder - Bei einigen Mustern handelt es sich um
Qeine negated_patternnot P₁und die Muster zusammenQmit den Werten, die nicht mitP₁jedem möglichen Wert übereinstimmenT. Ein negated_patternnot P₁ist selbst erschöpfend, wennP₁er keinen möglichen Wert vonT; oder - Bei einigen Mustern handelt es sich um
Qeine conjunctive_patternP₁ and P₂, und der Satz, der nurP₁erschöpfend ist, und der Satz, der nurP₂erschöpfend ist, ist erschöpfendTfürT.
Hinweis: Wenn ein Typmuster nullwerte Typen enthält, kann das Muster für den Typ erschöpfend sein, aber dennoch eine Warnung generieren, da das Typmuster nicht mit einem
nullWert übereinstimmt. Endnote
Hinweis: Bei Gleitkommatypen ist die Kombination von Mustern
< 0und>= 0nicht erschöpfend, da keine relationalen Muster übereinstimmenNaN. Ein korrekter erschöpfender Satz wäre< 0,>= 0unddouble.NaN(oderfloat.NaN). Endnote
Beispiel:
static void M(byte b) { switch (b) { case 0: case 1: case 2: ... // handle every specific value of byte break; // error: the pattern 'byte other' is subsumed by the (exhaustive) // previous cases case byte other: break; } }Endbeispiel
ECMA C# draft specification