Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
11.1 Общие
Шаблон — это синтаксическая форма, которую можно использовать с is оператором (§12.15.12), в switch_statement (§13.8.3) и в switch_expression (§12.12) для выражения формы данных, с которой сравниваются входящие данные. Шаблоны могут быть рекурсивными, чтобы части данных могли быть сопоставлены с вложенными шаблонами.
Шаблон проверяется на соответствие значению в ряде контекстов:
- В инструкции switch шаблон метки регистра проверяется в выражении инструкции switch.
- В операторе is-patternшаблон справа проверяется с выражением слева.
- В выражении коммутатора шаблонswitch_expression_arm проверяется на выражение в левой части выражения switch-expression.
- В вложенных контекстах вложенный шаблон проверяется на значения, полученные из свойств, полей или индексированных из других входных значений в зависимости от формы шаблона.
Значение, по которому проверяется шаблон, называется входным значением шаблона.
Формы шаблонов 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
;
parenthesized_pattern
: '(' pattern ')'
;
'(' pattern ')' Рабочая среда позволяет заключать шаблон в скобки, чтобы обеспечить порядок оценки между шаблонами, объединенными с помощью одного из logical_patterns.
Некоторые шаблонымогут привести к объявлению локальной переменной.
Каждая форма шаблона определяет набор типов входных значений, к которым может применяться шаблон. Шаблон 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.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.
Тип среды выполнения значения проверяется на тип в шаблоне, используя те же правила, указанные в операторе is-type (§12.15.12.1). Если тест выполнен успешно, шаблон соответствует указанному значению. Это ошибка во время компиляции, если тип является типом значения null (§8.3.12) или типом ссылки, допускающей значение NULL (§8.9.3). Эта форма шаблона никогда не соответствует значению null .
Примечание. Выражение
e is Tis-type и шаблонe is T _объявления эквивалентны, еслиTне является типом NULL. конечная заметка
Учитывая входное значение шаблона (§11.1) e, если simple_designationdiscard_designation, он обозначает отмену (§9.2.9.2), а значение e не привязано ни к чему. (Хотя объявленная переменная с именем _ может находиться в области в этой точке, эта именованной переменной не рассматривается в этом контексте.) В противном случае, если simple_designation single_variable_designation, вводятся локальная переменная (§9.2.9) заданного типа, именуемого заданным идентификатором. Эта локальная переменная назначается значение входного значения шаблона, если шаблон соответствует значению.
Некоторые сочетания статического типа входного значения шаблона и заданного типа считаются несовместимыми и приводят к ошибке во время компиляции. Значение статического типа E , как утверждается, совместимо с типом T , если существует преобразование удостоверений, неявное или явное преобразование ссылок, преобразование бокса, преобразование распаковки или неявное или явное преобразование типа ETзначений, допускающего значение NULL, или ET если либо или является открытым типом (§8.4.3). Шаблон объявления, именующий тип T , применим к каждому типу E , для которого 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преобразованное значение равно
- Если тип входного значения шаблона является целочисленным или типом перечисления, значение константы шаблона преобразуется в этот тип; иначе
- Если тип входного значения шаблона — это версия целочисленного типа или типа перечисления, константное значение шаблона, преобразованное в его базовый тип; иначе
- значение константы шаблона.
Учитывая входное значение шаблона e и константный шаблон P с преобразованным значением v,
-
Значение e, если имеет целочисленный тип или тип перечисления, или пустую форму одного из них, и v имеет целочисленный тип, шаблон
Pсоответствует значению e, если результат выраженияe == vимеетtrueзначение ; в противном случае - Шаблон
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 метод (§12.7) и выполняет дальнейшее сопоставление шаблонов в результирующих значениях. Он также поддерживает синтаксис шаблонов, аналогичный кортежам (без предоставленного типа), если тип входного значения совпадает с типом, содержащим Deconstruct, или если тип входного значения является типом кортежа, или если тип входного значения является object или System.ITuple типом среды выполнения выражения System.ITuple.
positional_pattern
: type? '(' subpatterns? ')' property_subpattern? simple_designation?
;
subpatterns
: subpattern (',' subpattern)*
;
subpattern
: pattern
| identifier ':' pattern
;
Учитывая совпадение входного значения сподпаттернами(типа) шаблона, метод выбирается путем поиска в типе объявлений для доступных Deconstruct объявлений и выбора одного из них с использованием одних и того же правила, что и для объявления деконструкции.
Это ошибка, если positional_pattern окупает тип, имеет один подпаттерн без идентификатора, не имеет property_subpattern и не имеет simple_designation. Это отличается от constant_pattern , которое скобок и positional_pattern.
Чтобы извлечь значения, соответствующие шаблонам в списке,
- Если тип опущен, а тип входного выражения является типом кортежа, число подпаттернов должно совпадать с кратностью кортежа. Каждый элемент кортежа сопоставляется с соответствующим подпаттерном, и совпадение завершается успешно, если все эти элементы успешно выполнены. Если в подпаттерне есть идентификатор, то он должен назвать элемент кортежа в соответствующей позиции в типе кортежа.
- В противном случае, если подходящее
Deconstructзначение существует в качестве члена типа, это ошибка во время компиляции, если тип входного значения не совместим с типом. Во время выполнения входное значение проверяется на тип. Если это не удается, то совпадение позиционного шаблона завершается ошибкой. При успешном выполнении входное значение преобразуется в этот тип иDeconstructвызывается с новыми переменными, созданными компилятором, для получения выходных параметров. Каждое полученное значение сопоставляется с соответствующим подпаттерном, и совпадение завершается успешно, если все эти значения успешно выполнены. Если какой-либо подпаттерн имеет идентификатор, то он должен присвоить параметру соответствующее положениеDeconstruct. - В противном случае, если тип опущен, и входное значение имеет тип
objectили какой-либо тип, который можно преобразовать вSystem.ITupleнеявное преобразование ссылок, и идентификатор не отображается среди подпаттернов, то совпадение используетсяSystem.ITuple. - В противном случае шаблон является ошибкой во время компиляции.
Порядок сопоставления подпаттернов во время выполнения не определен, и неудачное совпадение может не пытаться соответствовать всем подпаттернам.
Пример. Здесь мы деконструируем результат выражения и сопоставляем полученные значения с соответствующими вложенными шаблонами:
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 (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); }Выходные данные создаются
Sum of [10 20 30] is 60пример конца
Шаблон свойств 11.2.6
Property_pattern проверяет, не nullсоответствует ли входное значение и рекурсивно сопоставляет значения, извлеченные с помощью доступных свойств или полей.
property_pattern
: type? property_subpattern simple_designation?
;
property_subpattern
: '{' '}'
| '{' subpatterns ','? '}'
;
Это ошибка, если какой-либо подпаттернproperty_pattern не содержит идентификатор.
Это ошибка во время компиляции, если тип является типом значения 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 {}) ...конечная заметка
Учитывая совпадение выражения e сподпаттернами{типа} шаблона, это ошибка во время компиляции, если выражение e не совместимо с типом T, указанным по типу. Если тип отсутствует, предполагается, что тип является статическим типом e. Каждый идентификатор, отображаемый в левой части его подпаттернов, должен назначить доступное для чтения свойство или поле T. Если simple_designation property_pattern присутствует, он объявляет переменную шаблона типа T.
Во время выполнения выражение проверяется на T. Если это не удается, совпадение шаблона свойства завершается ошибкой, и результатом является false. В случае успешного выполнения каждое property_subpattern поле или свойство считывается, а его значение соответствует соответствующему шаблону. Результат всего совпадения заключается false только в том случае, если результат любого из них false. Порядок сопоставления подпаттернов не указан, и не удалось проверить все подпаттерны во время выполнения. Если совпадение выполнено успешно, и simple_designationproperty_pattern является single_variable_designation, объявленная переменная назначается соответствующее значение.
Property_pattern можно использовать для сопоставления шаблонов с анонимными типами.
Пример:
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
: '_'
;
Это ошибка во время компиляции для использования шаблона отмены в relational_expression формы relational_expressionisили в качестве шаблона switch_label.
Примечание. В этих случаях для сопоставления любого выражения используйте 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выражение обрабатывает все возможные входные значения. пример конца
Шаблон типа 11.2.8
Type_pattern используется для проверки того, что входное значение шаблона (§11.1) имеет заданный тип.
type_pattern
: type
;
Шаблон типа, именующий типT, применим к каждому типуE, для T которого E совместим шаблон (§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, longdecimalintushortuintulongshortbytefloatdoublecharnintи 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являются короткими операторами.
Это ошибка во время компиляции для переменной шаблона, объявленной под оператором шаблона или or шаблономnot.
Примечание. Поскольку ни один из них не
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) 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}");Выходные данные создаются
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.3 Подсемпция шаблона
В инструкции switch это ошибка, если шаблон дела подмечен предыдущим набором незащищенных случаев (§13.8.3). В неофициальном порядке это означает, что любое входное значение было бы сопоставлено одним из предыдущих случаев. Следующие правила определяют, когда набор шаблонов подмножет заданный шаблон:
Шаблон Pбудет соответствовать константе K , если какое-либо из следующих условий хранится:
- Спецификация поведения среды выполнения этого шаблона соответствует
PK. -
Pявляется type_pattern для типаTи неnullявляется, аKтипKсреды выполнения являетсяTили типом, производным отTили типом, реализующимT. -
P— это relational_pattern с оператором "op" и константойv, а выражениеK"op"vбудет оцениватьсяtrue. -
Pявляется negated_patternnot P₁иP₁не соответствуетK. -
P— это conjunctive_patternP₁ and P₂, и обаP₁совпадаютKиP₂будут соответствоватьK. -
P— это disjunctive_patternP₁ or P₂иP₁либо совпадатьK, либоP₂совпадатьK. -
P— это discard_pattern.
Набор шаблонов Qподменимирует шаблон P , если какое-либо из следующих условий хранится:
-
P— это константный шаблон, и любой из шаблонов в набореQбудет соответствоватьPпреобразованном значению. -
P— это шаблон var, и набор шаблоновQявляется исчерпывающим. -
P— это шаблон объявления с типом, и набор шаблоновTявляетсяQдля типаT(§11.4). -
P— это type_pattern для типаT, и набор шаблоновQявляется исчерпывающим для типаT. -
P— это relational_pattern с оператором "op" и константным значениемv, а для каждого значения входного типа, удовлетворяющего отношению "op"v, некоторые шаблоны в набореQбудут соответствовать значению. -
P— это disjunctive_patternP₁ or P₂иQнабор подсуменовP₁P₂шаблоновQ. -
P— это conjunctive_patternP₁ and P₂и по крайней мере один из следующих удержаний:QподсумыP₁илиQвложенныеP₂элементы. -
Pявляется negated_patternnot P₁иQявляется исчерпывающим для входного типа, учитывая только значения, не соответствующиеP₁. -
P— это discard_pattern , и набор шаблоновQявляется исчерпывающим для типа входного значения шаблона, а входное значение шаблона не является типом null или каким-либо шаблоном вQсопоставленииnull. - Некоторые шаблоны в
Qэтом случае — это disjunctive_patternQ₁ or Q₂и замена этого шаблонаQ₁вQнаборе, который подсумываетP, или заменять егоQ₂набором, который подсумываетP. - Некоторые шаблоны являются
Qnegated_patternnot Q₁иPне соответствуют ни одному значению, котороеQ₁будет соответствовать.
11.4. Исчерпывающая схема
Неформальным образом набор шаблонов является исчерпывающим для типа, если для каждого возможного значения этого типа, отличного от NULL, применяется некоторый шаблон в наборе. Следующие правила определяют, когда набор шаблонов является исчерпывающим для типа:
Набор шаблонов Q является исчерпывающим:
-
Tявляется целочисленным или типом перечисления или версией, допускающей значение NULL, и для каждого из возможных значенийTбазового типа, не допускающего значения NULL, некоторые шаблоны будутQсоответствовать значению этого значения; или - Некоторые шаблоны в
Qшаблоне var; или - Некоторые шаблоны являются
Qшаблоном объявления для типаD, и существует преобразование удостоверений, неявное преобразование ссылок или преобразование бокса изTD; или - Некоторые шаблоны являются
Qtype_pattern для типаD, и существует преобразование удостоверений, неявное преобразование ссылок или преобразование бокса изTD; или - В некоторых шаблонах
Qиспользуется discard_pattern; или - Шаблоны включают
Qсочетание relational_patternи constant_pattern, диапазоны которых коллективно охватывают все возможные значенияTбазового типа, не допускающего значения NULL. Дляfloatиdoubleтипов это включаетSystem.Double.NaNилиSystem.Single.NaNсоответственно, так какNaNне соответствует ни одному реляционному шаблону; - Некоторые шаблоны являются
Qdisjunctive_patternP₁ or P₂и заменяют этот шаблон какP₁в том, так иP₂вQдает набор, который является исчерпывающим дляT; или - Некоторые шаблоны являются
Qnegated_patternnot P₁, а шаблоны вместеQсо значениями, не соответствующимиP₁каждому возможномуTзначению. Negated_patternnot P₁является исчерпывающим сам по себе, еслиP₁не соответствует возможномуTзначению ; или - Некоторые шаблоны являются
Qconjunctive_patternP₁ and P₂, а набор, содержащий толькоP₁, является исчерпывающим, и набор, содержащий толькоP₂, являетсяисчерпывающимT.T
Примечание. Если шаблон типа включает типы, допускающие значение NULL, шаблон может быть исчерпывающим для типа, но по-прежнему создает предупреждение, так как шаблон типа не будет соответствовать значению
null. конечная заметка
Примечание. Для типов с плавающей запятой сочетание шаблонов
< 0и>= 0не является исчерпывающим, так как ни реляционный шаблон не соответствуетNaN. Правильный исчерпывающий набор будет< 0иметь значение ,>= 0иdouble.NaN(илиfloat.NaN). конечная заметка
Пример:
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; } }пример конца
ECMA C# draft specification