Поделиться через


11 Шаблонов и сопоставления шаблонов

11.1 Общие

Шаблон — это синтаксическая форма, которая может использоваться с is оператором (§12.12.12) и в switch_statement (§13.8.3) для выражения формы данных, с которыми следует сравнивать входящие данные. Шаблон проверяется на выражение инструкции switch или на relational_expression, которая находится в левой части оператора, каждая из которых называется входным значением isшаблона.

Формы шаблонов 11.2

11.2.1 Общие

Шаблон может иметь одну из следующих форм:

pattern
    : declaration_pattern
    | constant_pattern
    | var_pattern
    ;

Declaration_pattern и var_pattern могут привести к объявлению локальной переменной.

Каждая форма шаблона определяет набор типов входных значений, к которым может применяться шаблон. Шаблон P применяется к типу T , если T относится к типам, значения которых могут соответствовать шаблону. Это ошибка во время компиляции, если шаблон отображается в программе для сопоставления входного значения шаблона P (§11.1) типа T , если P к нему неприменимо T.

Пример. В следующем примере возникает ошибка во время компиляции, так как тип времени компиляции v имеет значение TextReader. Переменная типа TextReader никогда не может иметь значение, совместимое со ссылкой:string

TextReader 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 может иметь значение, совместимое со ссылкой:string

object v = Console.In;
if (v is string s)
{
    // code assuming v is a string
}

пример конца

Каждая форма шаблона определяет набор значений, для которых шаблон соответствует значению во время выполнения.

Шаблон объявления 11.2.2

Declaration_pattern используется для проверки того, что значение имеет заданный тип и, если тест успешно выполнен, укажите значение в переменной этого типа.

declaration_pattern
    : type simple_designation
    ;
simple_designation
    : single_variable_designation
    ;
single_variable_designation
    : identifier
    ;

Тип среды выполнения значения проверяется на тип в шаблоне, используя те же правила, указанные в операторе is-type (§12.12.12.12.1). Если тест выполнен успешно, шаблон соответствует указанному значению. Это ошибка во время компиляции, если тип является типом значения, допускающего значение NULL (§8.3.12). Эта форма шаблона никогда не соответствует значению null .

Примечание. Выражение e is T is-type и шаблон e is T _ объявления эквивалентны, если T не является пустым. конечная заметка

Учитывая входное значение шаблона (§11.1) e, если simple_designation являетсяидентификатором , он обозначает отмену (§9.2.9.2) и значение e не привязано ни к чему. (Хотя объявленная переменная с именем _ может находиться в области видимости в этот момент, эта именованная переменная не используется в этом контексте.) Если simple_designation является любым другим идентификатором, то вводится локальная переменная (§9.2.9.1) заданного типа, названной заданным идентификатором. Эта локальная переменная назначается значение входного значения шаблона, если шаблон соответствует значению.

Некоторые сочетания статического типа входного значения шаблона и заданного типа считаются несовместимыми и приводят к ошибке во время компиляции. Значение статического типаE, как утверждается, совместимо с типомT, если существует преобразование удостоверений, неявное или явное преобразование ссылок, преобразование бокса или распаковка преобразования из ET, или если 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.

Пример. Шаблон объявления можно использовать для проверки значений типов, допускающих значение 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 внутри блока. пример конца

11.2.3 Константный шаблон

Constant_pattern используется для проверки значения входного значения шаблона (§11.1) с заданным константным значением.

constant_pattern
    : constant_expression
    ;

Шаблон константы применим к типу, если существует неявное преобразование из константного PT

Для константного шаблона 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
    ;

Учитывая входное значение шаблона (§11.1) e, если обозначение является идентификатором _, это обозначает отброс (§9.2.9.2), и значение e не связано ни с чем. (Хотя объявленная переменная с таким именем может находиться в области действия в данной точке, эта именованная переменная не рассматривается в этом контексте.) Если обозначение является другим идентификатором, то в процессе выполнения значение e привязано к недавно введенной локальной переменной (§9.2.9.1) с таким именем, тип которой является статическим типом e, а входное значение шаблона назначается этой локальной переменной.

Это ошибка, если имя var привязывается к типу, в котором используется var_pattern .

11.3 Подсемпция шаблона

В инструкции switch это ошибка, если шаблон дела подмечен предыдущим набором незащищенных случаев (§13.8.3). В неофициальном порядке это означает, что любое входное значение было бы сопоставлено одним из предыдущих случаев. Следующие правила определяют, когда набор шаблонов подмножет заданный шаблон:

Шаблон Pбудет соответствовать константеK, если спецификация для поведения среды выполнения этого шаблона соответствуетPK.

Набор шаблонов Qподменимирует шаблон P , если какое-либо из следующих условий хранится:

  • P— это константный шаблон, и любой из шаблонов в наборе Q будет соответствовать Pпреобразованном значению.
  • P— это шаблон var, и набор шаблонов Q является исчерпывающимnull.
  • P— это шаблон объявления с типом, и набор шаблонов T является Q для типа T (§11.4).

11.4. Исчерпывающая схема

Неформальным образом набор шаблонов является исчерпывающим для типа, если для каждого возможного значения этого типа, отличного от NULL, применяется некоторый шаблон в наборе. Следующие правила определяют, когда набор шаблонов является исчерпывающим для типа:

Набор шаблонов Q является исчерпывающимT:

  1. T является целочисленным или типом перечисления или версией, допускающей значение NULL, и для каждого из возможных значений Tбазового типа, не допускающего значения NULL, некоторые шаблоны будут Q соответствовать значению этого значения; или
  2. Некоторые шаблоны в Q шаблоне var; или
  3. Некоторые шаблоны в Q шаблоне D

Пример:

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;
    }
}

пример конца