Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
11.1 Общие
Шаблон можно использовать с оператором is (§12.15.12), в switch_statement (§13.8.3) и в switch_expression (§12.12), чтобы описать форму данных, с которой сравниваются входящие данные. Шаблоны могут быть вложенными, с частями данных, которые сопоставляются с вложенными шаблонами.
Шаблон проверяется на соответствие значению в ряде контекстов:
- В switch_statementшаблонswitch_label проверяется на selector_expressionswitch_statement.
- При использовании оператора is-patternшаблон справа проверяется на выражение слева.
- В switch_expressionшаблонswitch_expression_arm проверяется на выражение в левой части switch_expression.
- В вложенных контекстах вложенный шаблон проверяется на значения, полученные из свойств, полей или индексированных из других входных значений в зависимости от формы шаблона.
Значение, по которому проверяется шаблон, называется входным значением шаблона.
Шаблон Pподмечен набором незащищенных шаблонов Q , если любое входное значение, соответствующее P одному из элементов Q.
В инструкции switch (§13.8.3) возникает ошибка, если шаблон дела подмечен предыдущим набором незащищенных случаев (§13.8.3). В выражении коммутатора (§12.12) это ошибка, если шаблон switch_expression_armподмечен предыдущим набором незащищенных шаблонов switch_expression_arm.
Набор шаблонов является исчерпывающим, если для каждого возможного входного значения применяется некоторый шаблон в наборе. Когда реализация обнаруживает, что набор шаблонов не является исчерпывающим, он должен выдавать предупреждение.
Формы шаблонов 11.2
11.2.1 Общие
Шаблон может иметь одну из следующих форм:
pattern
: logical_pattern
;
primary_pattern
: parenthesized_pattern
| declaration_pattern
| constant_pattern
| var_pattern
| positional_pattern
| property_pattern
| discard_pattern
| type_pattern
| relational_pattern
| list_pattern
| slice_pattern
;
parenthesized_pattern
: '(' pattern ')'
;
'(' pattern ')' Рабочая среда позволяет заключать шаблон в скобки, чтобы обеспечить порядок оценки между шаблонами, объединенными с помощью одного из logical_patterns.
Если входные данные можно синтаксически распознать как constant_pattern , так и positional_pattern , то будет выбрана constant_pattern .
Некоторые шаблонымогут привести к объявлению локальной переменной.
Каждая форма шаблона определяет набор типов входных значений, к которым может применяться шаблон. Шаблон P применяется к типу T , если T относится к типам, значения которых могут соответствовать шаблону. Это ошибка во время компиляции, если шаблон отображается в программе для сопоставления входного значения шаблона P (§11.1) типа T , если P к нему неприменимо T.
Пример. В следующем примере возникает ошибка во время компиляции, так как тип времени компиляции
vимеет значениеTextReader. Переменная типаTextReaderникогда не может иметь значение, совместимое со ссылкой:stringTextReader v = Console.In; // compile-time type of 'v' is 'TextReader' if (v is string) // compile-time error { // code assuming v is a string }Однако следующее не создает ошибку во время компиляции, так как тип времени компиляции
vимеет значениеobject. Переменная типаobjectможет иметь значение, совместимое со ссылкой:stringobject v = Console.In; if (v is string s) { // code assuming v is a string }пример конца
Каждая форма шаблона определяет набор значений, для которых шаблон соответствует значению во время выполнения.
Порядок оценки операций и побочных эффектов во время сопоставления шаблонов (вызовы Deconstruct, доступ к свойствам и вызовы элементов System.Runtime.CompilerServices.ITuple) не указаны.
Шаблон объявления 11.2.2
Declaration_pattern используется для проверки того, что значение имеет заданный тип и, если тест выполнен успешно, при необходимости укажите значение в переменной этого типа.
declaration_pattern
: type simple_designation
;
simple_designation
: discard_designation
| single_variable_designation
;
discard_designation
: '_'
;
single_variable_designation
: identifier
;
При признании simple_designation , если применяются discard_designation иsingle_variable_designation альтернативные варианты, то следует выбрать прежнее.
Примечание. ANTLR автоматически делает указанный выбор из-за упорядочения альтернатив simple_designation. конечная заметка
Это ошибка во время компиляции, если тип является типом значения null (§8.3.12) или типом ссылки, допускающей значение NULL (§8.9.3).
Тип среды выполнения значения проверяется на тип в шаблоне, используя те же правила, указанные в операторе is-type (§12.15.12.1). Если тест выполнен успешно, шаблон соответствует указанному значению.
Примечание. Выражение
e is Tтипа и шаблонe is T _объявления эквивалентны, если оба являются допустимыми. конечная заметка
Учитывая входное значение шаблона (§11.1) e, если simple_designation является discard_designation, обозначая отмену (§9.2.9.2), значение e не привязано к чему-либо. В противном случае, если simple_designation является single_variable_designation, представлена локальная переменная (§9.2.9) заданного типа, именуемого заданным идентификатором. Эта локальная переменная назначается значение входного значения шаблона, если шаблон соответствует значению.
Примечание. Это лечение
_внутри declaration_pattern отличается от того,_что автономное письмо, написанное как шаблон (§11.2.7): в последнем случае константа области или тип с именем_, если таковые имеются, не скрыты. конечная заметка
Как сообщается, тип Eсовместим с типом T , если существует преобразование удостоверений, неявное или явное преобразование ссылок, преобразование бокса, преобразование распаковки или неявное или явное преобразование ETтипа значений, допускающего значение NULL, или если ET это открытый тип (§8.4.3). Шаблон объявления, именующий тип T, применим к (§11.2.1), для которого EE совместим Tшаблон. Это ошибка во время компиляции, если шаблон объявления, именующий тип T , используется для сопоставления входного значения шаблона (§11.1), статический тип E которого несовместим с Tшаблоном.
Примечание. Поддержка открытых типов может оказаться наиболее полезной при проверке типов, которые могут быть либо структурой, либо типами классов, а бокс следует избежать. конечная заметка
Пример. Шаблон объявления полезен для выполнения тестов типов времени выполнения ссылочных типов и заменяет идиом
var v = expr as Type; if (v != null) { /* code using v */ }с немного более кратким
if (expr is Type v) { /* code using v */ }пример конца
Пример. Шаблон объявления можно использовать для проверки значений типов, допускающих значение NULL: значение типа (или поля
Nullable<T>) соответствует шаблонуTтипаT2 id, если значение не равно null иT2имеетTзначение, или какой-либо базовый тип или интерфейсT. Например, в фрагменте кодаint? x = 3; if (x is int v) { /* code using v */ }Условие инструкции
ifнаходитсяtrueво время выполнения, а переменнаяvсодержит значение3типаintвнутри блока. После блокировки переменнаяvнаходится в области, но не определенно назначена. пример конца
11.2.3 Константный шаблон
Constant_pattern используется для проверки значения входного значения шаблона (§11.1) с заданным константным значением.
constant_pattern
: constant_expression
;
Шаблон P константы применим к типу, если имеется неявное преобразование из константного выражения P типа в типTT, или если System.Span<char>T выражение является или System.ReadOnlySpan<char> константным выражением P типа string и не null является литеральным.
Для константного шаблона Pпреобразованное значение равно
- Если тип входного значения шаблона является целочисленным или типом перечисления, значение константы шаблона преобразуется в этот тип; иначе
- Если тип входного значения шаблона — это версия целочисленного типа или типа перечисления, константное значение шаблона, преобразованное в его базовый тип; иначе
- значение константы шаблона.
Учитывая входное значение шаблона e и константный шаблон P с преобразованным значением v,
-
Значение e, если имеет целочисленный тип или тип перечисления, или пустую форму одного из них, и v имеет целочисленный тип, шаблон
Pсоответствует значению e, если результат выраженияe == vимеетtrueзначение ; в противном случае - Значение
< a0/>, если e имеет типили v является константной строкой, и v не имеет константного значения, шаблон соответствует значениюe , есливозвращается ; в противном случае - Шаблон
Pсоответствует значению e, если возвращаетсяobject.Equals(e, v).true
Пример. Оператор
switchв следующем методе использует пять постоянных шаблонов в метках регистра.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(...); } }пример конца
Шаблон Var 11.2.4
Var_pattern соответствует каждому значению. То есть операция сопоставления шаблонов с var_pattern всегда выполняется успешно.
Var_pattern применимо к каждому типу.
var_pattern
: 'var' designation
;
designation
: simple_designation
| tuple_designation
;
tuple_designation
: '(' designations? ')'
;
designations
: designation (',' designation)*
;
Учитывая входное значение шаблона (§11.1) e, если обозначениеdiscard_designation, оно обозначает отмену (§9.2.9.2), а значение e не привязано к чему-либо. (Хотя объявленная переменная с таким именем может находиться в области в этой точке, эта именованной переменной не рассматривается в этом контексте.) В противном случае, если присвоениеsingle_variable_designation, во время выполнения значение e привязано к недавно введенной локальной переменной (§9.2.9) этого имени, тип которого является статическим типом e, а входное значение шаблона назначается этой локальной переменной.
Это ошибка, если имя var привязывается к типу, в котором используется var_pattern .
Если обозначение является tuple_designation, шаблон эквивалентен positional_pattern (§11.2.5) (var формы, ...
) где обозначениянаходятся в tuple_designation. Например, шаблон var (x, (y, z)) эквивалентен (var x, (var y, var z)).
11.2.5 Позиционный шаблон
Positional_pattern проверяет, не nullявляется ли входное значение, извлекает из него последовательность значений и сопоставляет каждое извлеченное значение с соответствующим подпаттерном. Значения извлекаются одним из трех способов: рассматривая входные данные как кортеж, вызывая Deconstruct метод или индексируя входные данные через System.Runtime.CompilerServices.ITuple.
Примечание. Использование
Deconstructздесь отличается от преобразования деконструкции исходного уровня, определенного в §12.7. конечная заметка
positional_pattern
: type? '(' subpatterns? ')' property_subpattern? simple_designation?
;
subpatterns
: subpattern (',' subpattern)*
;
subpattern
: pattern
| subpattern_name ':' pattern
;
subpattern_name
: identifier
| subpattern_name '.' identifier
;
Пусть n будет числом подпаттернов, отображаемых между скобками. Стратегия сопоставления выбирается во время компиляции, применяя следующие варианты в порядке; первый случай, условия которого выполнены, используются, и остальные случаи не рассматриваются. После выбора дела эта стратегия фиксируется: любая ошибка во время компиляции, указанная в этом случае, и сопоставление не проходит до последующего случая.
- Форма кортежа. Если тип опущен, а статический тип входного значения является типом кортежа (§8.3.11) или если входное значение является литералом кортежа (§12.8.6), то этот случай применяется. Это ошибка во время компиляции, если n не равно arity этого типа кортежа. Во время выполнения каждый элемент кортежа соответствует соответствующему подпаттерну; Совпадение завершается успешно, если все из них успешно. Если в подпаттерне есть идентификатор, этот идентификатор должен назвать элемент кортежа в соответствующей позиции в типе кортежа.
- Форма деконструкция. В противном случае, если какой-либо типприсутствует, либо тип опущен, а статический тип входного значения содержит доступный
Deconstructметод (§12.7), то этот случай применяется. Разрешить D быть типом , если тип присутствует; в противном случае позволить D быть статическим типом входного значения.DeconstructМетод выбирается из D, используя те же правила разрешения перегрузки, что и для объявления деконструкции, с дополнительным требованием, что его числоoutпараметров равно n; это ошибка во время компиляции, если такой метод не существует. Если тип присутствует, это ошибка во время компиляции, если статический тип входного значения несовместим (§11.2.2) с типом; Во время выполнения входное значение проверяется на тип и, если этот тест завершается ошибкой, совпадение позиционного шаблона завершается ошибкой. В противном случае входное значение преобразуется в D , и выбранныйDeconstructметод вызывается с помощью свежих переменных, получающих егоoutпараметры. Каждое полученное значение сопоставляется с соответствующим подпаттерном, и совпадение завершается успешно, если все из них успешно. Если какой-либо подпаттерн имеет идентификатор, этот идентификатор должен присвоить этому параметру соответствующее положениеDeconstruct. - Форма ITuple. В противном случае, если тип опущен, подпаттерн не имеет идентификатора, а статический тип входного значения —
object,System.Runtime.CompilerServices.ITupleили тип, в который имеется неявное преобразованиеSystem.Runtime.CompilerServices.ITupleссылок, применяется этот случай. Во время выполнения входное значение проверяется для того, чтобы он не был экземпляромnullSystem.Runtime.CompilerServices.ITuple; если этот тест завершается ошибкой, совпадение позиционного шаблона завершается ошибкой. В противном случае свойство значенияLengthсчитывается и, если оно не равно n, совпадение позиционного шаблона завершается ошибкой. В противном случае для каждого значения i от 1 до n значение, полученное путем индексирования входного значения с i – 1, совпадает с подпаттерномi-th, и совпадение успешно, если все из них успешно. - В противном случае не применяется никаких случаев, и positional_pattern является ошибкой во время компиляции.
Порядок сопоставления подпаттернов во время выполнения не определен, и неудачное совпадение может не пытаться соответствовать всем подпаттернам.
Пример. Здесь мы деконструируем результат выражения и сопоставляем полученные значения с соответствующими вложенными шаблонами:
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); }пример конца
Пример. Имена элементов кортежа и деконструкционных параметров можно использовать в позиционной схеме следующим образом:
var numbers = new List<int> { 10, 20, 30 }; if (SumAndAverage(numbers) is (Sum: var sum, Average: var average)) { Console.WriteLine($"Sum of [{string.Join(" ", numbers)}] is {sum}; average is {average}"); } else { // Note: sum and average are in scope here, but not definitely assigned Console.WriteLine("No numbers provided to compute sum and average."); } static (double Sum, double Average)? SumAndAverage(IEnumerable<int> numbers) { int sum = 0; int count = 0; foreach (int number in numbers) { sum += number; count++; } return count == 0 ? null : (sum, sum / count); }Выходные данные создаются
Sum of [10 20 30] is 60; average is 20пример конца
Шаблон свойств 11.2.6
Property_pattern проверяет, не nullсоответствует ли входное значение и рекурсивно сопоставляет значения, извлеченные с помощью доступных свойств или полей.
property_pattern
: type? property_subpattern simple_designation?
;
property_subpattern
: '{' '}'
| '{' subpatterns ','? '}'
;
Это ошибка, если какой-либо подпаттернproperty_pattern не содержит subpattern_name.
Это ошибка во время компиляции, если тип является типом значения null (§8.3.12) или типом ссылки, допускающей значение NULL (§8.9.3).
Примечание. Шаблон проверки null выходит из тривиального шаблона свойства. Чтобы проверить, является ли строка
sне null, можно написать любую из следующих форм:#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 {}) ...Пример объявления
x2аналогиченif (s is var x2)выводу типа переменной, но шаблон свойств гарантирует, чтоx2значение не равно null. конечная заметка
Учитывая совпадение выражения e сподпаттернами{типа} шаблона, это ошибка во время компиляции, если выражение e несовместимо с шаблоном (§11.2.2) с типомT, указанным по типу. Если тип отсутствует, предполагается, что тип является статическим типом e. Каждая subpattern_name, отображаемая в левой части его подпаттернов, должна назначить доступное для чтения свойство или поле T. Если simple_designation property_pattern присутствует, он объявляет переменную шаблона типа T.
Во время выполнения выражение проверяется на T. Если это не удается, совпадение шаблона свойства завершается ошибкой, и результатом является false. В случае успешного выполнения каждое property_subpattern поле или свойство считывается, а его значение соответствует соответствующему шаблону. Результат всего совпадения заключается false только в том случае, если результат любого из них false. Порядок сопоставления подпаттернов не указан, и не удалось проверить все подпаттерны во время выполнения. Если совпадение выполнено успешно, и simple_designationproperty_pattern является single_variable_designation, объявленная переменная назначается соответствующее значение.
Property_pattern можно использовать для сопоставления шаблонов с анонимными типами.
Subpattern_name может ссылать на вложенный элемент. В таком случае получатель для каждого подстановки имени является типом предыдущего члена T₀, начиная с типа входных данных property_pattern. Если T является типом, допускаемым значением NULL, T₀ является его базовым типом, в противном случае T₀ равен T. Например, шаблон формы { Prop1.Prop2: pattern } точно эквивалентен { Prop1: { Prop2: pattern } }.
Примечание. Это будет включать проверку null, если T является типом значений, допускаемым значением NULL, или ссылочным типом. Эта проверка null означает, что доступные вложенные свойства будут свойствами T₀, а не T. Так как разрешены повторяющиеся пути элементов, компиляция сопоставления шаблонов может воспользоваться общими частями шаблонов. конечная заметка
Пример:
var o = ...; if (o is string { Length: 5 } s) ...пример конца
Пример: проверка типа выполнения и объявление переменной можно добавить в шаблон свойств следующим образом:
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."), };Выходные данные создаются
Hello Hi! 12345 abcпример конца
Шаблон отмены 11.2.7
Каждое выражение соответствует шаблону отмены, что приводит к отмене значения выражения.
discard_pattern
: '_'
;
Где синтаксический контекст разрешает шаблон, если маркер _ будет разрешаться как simple_name (§12.8.4) к доступной константе или типу, то _он не рассматривается как discard_pattern. Вместо:
- При
_разрешении на доступную константу интерпретируется как_(§11.2.3), константное выражение которого является этой константой. - При
_разрешении типа в правой частиisоператора конструктор relational_expressionis _интерпретируется как оператор is-type (§12.15.12.1) для этого типа. В любом другом синтаксическом контексте, допускающего шаблон, голый_разрешение типа не является допустимым шаблоном. Однако может отображаться как_declaration_pattern (например,_ x) или в других формах шаблонов, которые явно называют тип.
Это правило сохраняет обратную совместимость с кодом, определенным _ как тип или идентификатор до внедрения шаблона отмены. Если _ разрешено что-либо другое, кроме доступной константы или типа (например, локальная переменная, параметр, поле или метод), правило не применяется и _ остается discard_pattern.
Примечание. Это аналогично правилу
varв §11.2.4, за исключением того, что для_константы или типа_области может быть интерпретировано как ссылка на это объявление, а не создание ошибки. конечная заметка
_ Если после применения предыдущего правила маркер по-прежнему является discard_pattern, это ошибка во время компиляции для этого discard_pattern отображаться как весь шаблон relational_expressionшаблона формы is или как весь шаблонswitch_label.
Однако discard_pattern может отображаться как подпаттерн включающего шаблона (например, как подпаттернpositional_pattern или property_pattern).
Примечание. В этих случаях для сопоставления любого выражения используйте var_pattern с отменой
var _. конечная заметка
Пример:
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, };Выходные данные создаются
5.0 0.0 0.0Здесь шаблон отмены используется для обработки
nullи любого целочисленного значения, которое не имеет соответствующегоDayOfWeekчлена перечисления. Это гарантирует, чтоswitchвыражение обрабатывает все возможные входные значения. пример конца
Пример. Ниже показано, как константа области с именем
_изменяет интерпретацию_руки вswitchвыражении. ВWithoutUnderscore,_рука является discard_pattern и соответствует любому значению. ВWithUnderscoreобласти константы__строка интерпретируется как constant_pattern , которая соответствует только значению0.static string WithoutUnderscore(int n) => n switch { 1 => "one", _ => "other", }; static string WithUnderscore(int n) { const int _ = 0; return n switch { 1 => "one", _ => "zero", var x => "other: " + x, }; }пример конца
Шаблон типа 11.2.8
Type_pattern используется для проверки того, что входное значение шаблона (§11.1) имеет заданный тип.
type_pattern
: type
;
Шаблон типа, именующий типT, применим к каждому типуE, для E которого совместим T (§11.2.2).
Тип среды выполнения проверяется на тип с использованием одинаковых правил, указанных в операторе is-type (§12.15.12.1). Если тест выполнен успешно, шаблон соответствует указанному значению. Это ошибка во время компиляции, если тип является типом, допускаемым значением NULL. Эта форма шаблона никогда не соответствует значению null .
11.2.9 Реляционный шаблон
Relational_pattern используется для реляционного тестирования входного значения шаблона (§11.1) с константным значением.
relational_pattern
: '<' relational_expression
| '<=' relational_expression
| '>' relational_expression
| '>=' relational_expression
;
Для вычисления константного значения требуется relational_expression в relational_pattern .
Реляционные шаблоны поддерживают реляционные операторы <, <=>и >= все встроенные типы, поддерживающие такие двоичные реляционные операторы с обоими операндами с одинаковым типом: sbyte, byteshortushortintuintlongulongcharfloatdoubledecimalnintи nuintперечисления.
Relational_patternприменимо к типуT, если подходящий встроенный двоичный реляционный оператор определен с обоими операндами типаT, или если явное преобразование null или распаковки существует из T типа константного выражения.
Это ошибка во время компиляции, если выражение оценивается как double.NaNfloat.NaN, или константой NULL.
Если входное значение имеет тип, для которого определен подходящий встроенный двоичный реляционный оператор, оценка этого оператора принимается в качестве значения реляционного шаблона. В противном случае входное значение преобразуется в тип константного выражения с помощью явного преобразования, допускающего значение NULL или распаковки. Это ошибка во время компиляции, если такого преобразования нет. Шаблон считается не соответствующим, если преобразование завершается ошибкой. Если преобразование выполнено успешно, результат операции сопоставления шаблонов является результатом оценки выражения e «op» v , в котором e преобразованные входные данные, "op" является реляционным оператором и v является константным выражением.
Пример:
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", };Выходные данные создаются
Too high Unknown Acceptableпример конца
11.2.10 Логический шаблон
Logical_pattern используется для отмены результата сопоставления шаблонов или объединения результатов нескольких совпадений шаблонов с помощью сочетания (and) или отсоединения (or).
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, andи or коллективно называются операторами шаблонов.
Negated_pattern совпадает, если шаблон отрицается не соответствует, и наоборот.
Для conjunctive_pattern требуется сопоставление обоих шаблонов.
Для disjunctive_pattern требуется сопоставление любого шаблона. В отличие от своих операторов языка, && и ||andне orявляются короткими операторами.
Это ошибка во время компиляции для переменной шаблона, объявленной под оператором шаблона или not шаблономor.
Примечание. Поскольку ни один из них не
notorможет создавать определенное назначение для переменной шаблона, это ошибка объявления одной из этих позиций. конечная заметка
В conjunctive_patternвходной тип второго шаблона сужается типом сужающих требований первого шаблона and.
Узкий тип шаблона P определяется следующим образом:
- Если
Pэто шаблон типа, узкий тип является типом типа шаблона типа. - В противном случае, если
Pэто шаблон объявления, узкий тип является типом типа шаблона объявления. - В противном случае, если
Pэто рекурсивный шаблон, предоставляющий явный тип, то узкий тип — это тип. - В противном случае, если
Pони соответствуют правиламITupleв positional_pattern (§11.2.5), то узкий тип — это типSystem.ITuple. - В противном случае, если
Pявляется константой, в которой константы не являются пустой константой и где выражение не имеет преобразования констант в входной тип, то узкий тип является типом константы. - В противном случае, если
Pэто реляционный шаблон, в котором константное выражение не имеет преобразования константного выражения в входной тип, то узкий тип является типом константы. - В противном случае, если
Pэтоorшаблон, узкий тип является общим типом узкого типа подпаттернов, если такой распространенный тип существует. Для этого алгоритм общего типа учитывает только удостоверения, боксы и неявные преобразования ссылок, а также рассматривает все подпаттерны последовательностиorшаблонов (игнорируя круглые скобки). - В противном случае, если
Pэто шаблон,andтип является узким типом правильного шаблона. Кроме того, узкий тип левого шаблона является типом входных данных правого шаблона. - В противном случае узкий
Pтип —Pвходной тип.
Примечание. Как указано грамматикой,
notимеет приоритет надand, который имеет приоритет надor. Это можно явно указать или переопределить с помощью круглых скобок. конечная заметка
Когда шаблон отображается справа isот справа, степень шаблона определяется грамматикой; в результате операторы шаблонов andorи not внутри шаблона привязываются более тесно, чем логические операторы&&, ||и ! вне шаблона.
Пример:
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", };Выходные данные создаются
High Too low Acceptableпример конца
Пример:
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}."), };Выходные данные создаются
winter autumn springпример конца
Пример:
object msg = "msg"; object obj = 5; bool flag = true; // This is parsed as: (msg is (not int) or string) bool 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 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}");Выходные данные создаются
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: Trueпример конца
Шаблон списка 11.2.11
List_pattern соответствует последовательности элементов в списке или массиве.
list_pattern
: list_pattern_clause simple_designation?
;
list_pattern_clause
: '[' (pattern (',' pattern)* ','?)? ']'
;
List_pattern совместим с любым типом, который можно считать (§18.1), а также индексируемым (§18.1)— он имеет доступный индексатор, который принимает в качестве аргумента или доступный индексатор с одним Indexint параметром. Если оба индексаторов присутствуют, то он предпочтителен. (Дополнительные сведения о поддержке неявного индекса см. в разделе §18.4.2 .)
Шаблон формы expr is [1, 2, 3] эквивалентен следующему коду:
expr.Length is 3
&& expr[new Index(0, fromEnd: false)] is 1
&& expr[new Index(1, fromEnd: false)] is 2
&& expr[new Index(2, fromEnd: false)] is 3
Пример:
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 and not 7]); // Trueпример конца
Шаблон отмены (§11.2.7) соответствует любому одному элементу.
Пример:
List<int> numbers = new() { 1, 2, 3 }; if (numbers is [_, var second, _]) { Console.WriteLine($"The second element is {second}."); }пример конца
Шаблон среза 11.2.12
Slice_pattern удаляет ноль или больше элементов. Он должен использоваться только непосредственно в list_pattern_clause, а затем только один раз в этом предложении.
slice_pattern
: '..' pattern?
;
Slice_pattern без подпаттерна совместим с любым типом, совместимым с list_pattern.
Slice_pattern с подпаттерном совместим с любым типом, который можно считать (§18.1), а также срезаемым (§18.1) — он имеет доступный индексатор, который принимает Range в качестве аргумента или доступный Slice метод с двумя int параметрами. Если оба присутствуют, то первый предпочтителен. (Дополнительные сведения о поддержке неявного индекса см. в разделе §18.4.2 .)
Slice_pattern действует как правильная отмена; То есть тесты не должны быть выполнены для такого шаблона. Скорее, это влияет только на другие узлы, а именно длину и индексатор. Например, шаблон формы expr is [1, .. var s, 3] эквивалентен следующему коду (если он совместим с явным Index и Range поддерживается):
expr.Length is >= 2
&& expr[new Index(0, fromEnd: false)] is 1
&& expr[new Range(new Index(1, fromEnd: false), new Index(1, fromEnd: true))] is var s
&& expr[new Index(1, fromEnd: true)] is 3
Тип входных данных для slice_pattern — это возвращаемый тип базового this[Range] или Slice метода с двумя исключениями: для stringмассивов и массивов string.Substring , а RuntimeHelpers.GetSubArrayтакже используется соответственно.
Пример. Шаблон среза можно использовать для сопоставления элементов только в начале или в конце входной последовательности.
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пример конца
Пример: подпаттерн может быть вложен в шаблон среза:
MatchMessage("aBBA"); // output: Message aBBA matches; inner part is BB. MatchMessage("apron"); // output: Message apron doesn't match. 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); } Validate(new[] { -1, 0, 1 }); // output: not valid Validate(new[] { -1, 0, 0, 1 }); // output: valid void Validate(int[] numbers) { var result = numbers is [< 0, .. { Length: 2 or 4 }, > 0] ? "valid" : "not valid"; Console.WriteLine(result); }пример конца
ECMA C# draft specification