Свойства и позиционные шаблоны

Tip

Эта статья является частью раздела "Основы" для разработчиков , которые уже знают хотя бы один язык программирования и учат C#. Начните с обзора сопоставления шаблонов , если вы не знакомы с шаблонами. Полные языковые правила см. в шаблонах свойств и позиционных шаблонах в справочнике по языку.

Шаблоны свойств и позиционные шаблоны оба проверяют части значения. Разница заключается в том, как они определяют эти части:

  • Шаблон свойства указывает свойства или поля, которые нужно проверять.
  • Позиционный шаблон определяет значения по их порядку.

Деконструкция предоставляет упорядоченный набор значений компонентов. Кортеж уже имеет порядок элементов; см. деконструкцию кортежей. Для другого типа Deconstruct метод определяет, какие значения компонентов предоставляются и их порядок.

Сравнение имен и позиций

Следующий шаблон сопоставления по свойствам проверяет два именованных свойства погодного показания со значениями температуры в градусах по Цельсию:

static bool IsHotAndHumid(WeatherReading reading) =>
    reading is { TemperatureC: > 30, HumidityPercent: > 70 };

sealed record WeatherReading(int TemperatureC, int HumidityPercent);

Следующий позиционный шаблон проверяет значение сигнала, после которого следует логическое значение:

static string GetCrossingInstruction(
    PedestrianSignal signal, bool crossingIsClear) =>
    (signal, crossingIsClear) switch
    {
        (PedestrianSignal.Walk, true) => "Cross now",
        (PedestrianSignal.Walk, false) => "Wait for the crossing to clear",
        _ => "Wait for the walk signal"
    };

enum PedestrianSignal
{
    Stop,
    Walk
}

Шаблон свойства определяет входные данные по именам TemperatureC и HumidityPercent. Код пересечения создает кортеж из отдельных signal и crossingIsClear значений. Затем шаблон кортежа идентифицирует эти значения по порядку: сначала signal, а затем crossingIsClear. Позиционный шаблон здесь удачно подходит, поскольку этот только что созданный кортеж содержит всего два значения, и их порядок имеет однозначный смысл при принятии решения о пересечении.

Выберите шаблон свойств, когда имена участников помогают объяснить тест. Шаблоны свойств обычно более понятны для классов, структур и записей. Выберите позиционный шаблон, если порядок уже придаёт значениям очевидный смысл. Позиционные шаблоны наиболее полезны для кортежей, которые объединяют несколько связанных значений в одно значение с фиксированным порядком.

Следуйте вложенным входным данным в рекурсивных шаблонах

Свойства и позиционные шаблоны являются рекурсивными шаблонами: они применяют другой шаблон к каждому свойству, полю или расположению, которые они выбирают. Выбранное значение становится входными данными в вложенный шаблон.

reading Выражение IsHotAndHumid— это входные данные в шаблон свойств. C# вычисляет это выражение перед сопоставлением. Шаблон получает два значения из результирующего объекта:

  • Реляционный шаблон > 30 проверяет значение TemperatureC.
  • Реляционный шаблон > 70 проверяет значение HumidityPercent.

Тест внешнего типа является необязательным, а предложения рекурсивных шаблонов могут быть пустыми. Например, шаблон { } пустого свойства соответствует любому вычисляемому значению, отличному от NULL.

Шаблоны свойств и позиционные шаблоны сопоставляются только с вычисленными значениями, отличными от NULL. Когда null входит в входной домен, выберите рекурсивный шаблон, который сначала проверяет значение, отличное от NULL:

static string DescribeNullableInput(object? value)
{
    if (value is not { } nonNullValue)
    {
        return "No value";
    }

    return nonNullValue switch
    {
        DateTime => "Date",
        string => "Text",
        _ => "Another type"
    };
}

Входное выражение — value. C# вычисляет это выражение, а шаблон свойства { } проверяет, что результирующее значение не равно null, перед его присваиванием переменной nonNullValue. Следующее выражение коммутатора может протестировать несколько возможных типов среды выполнения. Его DateTime и string шаблоны типов не имеют обозначения, так как метод должен определять только каждый тип, а не захватывать его значение.

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

Вы можете добавить тест типа перед фигурными скобками, когда входное выражение может создавать различные типы. Вы также можете использовать путь члена для тестирования вложенного свойства:

static string DescribeDate(object? value) =>
    value switch
    {
        DateTime { Date.DayOfWeek:
            DayOfWeek.Saturday or DayOfWeek.Sunday } => "Weekend date",
        DateTime => "Weekday date",
        null => "No date",
        _ => "Not a date"
    };

value — это входное выражение. C# сначала вычисляет это и проверяет, является ли полученное значение значением типа DateTime. Затем значение свойства Date используется как входные данные для обращения к члену DayOfWeek. Наконец, DayOfWeek значение становится входным в логический шаблон, который проверяет две константы. Сопоставление завершается успешно, если внешнее значение имеет указанный тип, и каждый объект, необходимый вдоль пути элемента, не имеет значения NULL.

Сравнение шаблонов с операторами ветвления

DescribeDate Предыдущий метод выражает четыре результата в виде шаблонов:

static string DescribeDate(object? value) =>
    value switch
    {
        DateTime { Date.DayOfWeek:
            DayOfWeek.Saturday or DayOfWeek.Sunday } => "Weekend date",
        DateTime => "Weekday date",
        null => "No date",
        _ => "Not a date"
    };

Следующий метод дает тот же результат с использованием последовательности императивных операторов ветвления:

static string DescribeDateWithBranches(object? value)
{
    if (value is DateTime date)
    {
        if (date.DayOfWeek == DayOfWeek.Saturday ||
            date.DayOfWeek == DayOfWeek.Sunday)
        {
            return "Weekend date";
        }

        return "Weekday date";
    }

    if (value is null)
    {
        return "No date";
    }

    return "Not a date";
}

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

См. также