Сопоставление с образцом на C#: объяснение и примеры

от автора

За годы своего развития C# существенно эволюционировал; одна из самых мощных фич языка — это сопоставление с образцом (pattern matching).

Работая недавно над небольшим хобби-проектом, я наткнулся на такую прекрасную строку кода C#.

if (person is not null and { Age: > 18 }) {}

Выглядит изящно. Откровенно говоря, она заставила меня призадуматься.

Годами я писал проверки на null и свойства-аксессоры классическим образом:

if (person != null && person.Age > 18) {}

Функционально? Да. Удобочитаемо? Не особо. Безопасно? Спорно, особенно когда код становится сложнее.

Я решил создать шорт YouTube об этом современном синтаксисе. Это небольшое забавное напоминание о том, что C# позволяет при помощи сопоставления с образцом комбинировать проверки на null и обращение к свойству в одно условие.

Я понятия не имел, что это короткое видео приведёт к гораздо более глубокому исследованию, и покажет мне, насколько полезно и универсально сопоставление с образцом в современном C#.

Эта фича повышает читаемость, уменьшает объём бойлерплейта и обеспечивает более выразительную обработку логики.

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

Всё началось с is… 

Меня одолевало любопытство.

Я уже знал о базовом ключевом слове is в C#. Вероятно, вы видели его тысячу раз:

if (obj is string s) {     Console.WriteLine($"It's a string: {s}"); }

Чего я не осознавал полностью, так это того, насколько ключевое слово is эволюционировало, позволив обрабатывать типы, условия, свойства и даже сложные объекты; и всё это в одной строке.


Что такое сопоставление с образцом? 

Сопоставление с образцом — это механизм, позволяющий сравнивать значение на входе с образцом и предпринимать действия, если оно ему соответствует. В C# сопоставление с образцом поддерживается в следующих конструкциях:

  • выражения is

  • операторы switch

  • выражения switch

C# поддерживает широкий спектр образцов, каждый из которых мы рассмотрим один за другим.


1. Образцы объявления и типов

Эти образцы проверяют тип объекта в среде выполнения и опционально присваивают его новой переменной.

Пример:

object item = "Welcome!"; if (item is string text) {     Console.WriteLine(text.ToUpper()); // Вывод: WELCOME! }

Аналогия из реального мира: представьте, что покупатель — это объект. Если это PremiumCustomer, то мы можем привести тип и применить особые правила.


2. Образцы констант

Их можно использовать для сравнения значения непосредственно с константой. Это более краткая альтернатива нескольким операторам if.

Пример:

int guests = 2; string table = guests switch {     1 => "Single Table",     2 => "Couple Booth",     4 => "Family Table",     _ => "Group Table" };

Например, ресторан может бронировать столы в зависимости от количества людей.


3. Образцы отношений

Эти образцы позволяют сравнивать значение и константу (меньше, больше или равно).

Пример:

double temperature = 35.2;  string category = temperature switch {     < 0 => "Freezing",     >= 0 and < 20 => "Cold",     >= 20 and <= 30 => "Warm",     > 30 => "Hot",     _ => "Unknown" };

Отлично подходит для таких сценариев, как категоризация погоды или систем оценок.


4. Логические образцы

Комбинирование образцов при помощи andor и not.

Пример:

int age = 25; bool isYoungAdult = age is >= 18 and <= 30;

Для исключения можно использовать not:

if (user is not null) {     // user валиден }

Логические образцы позволяют создавать более сложные деревья решений с меньшим количеством шума.

5. Образцы свойств

Сопоставление на основании значений свойств внутри объекта.

Пример:

var booking = new { RoomType = "Suite", Guests = 2 };  if (booking is { RoomType: "Suite", Guests: > 1 }) {     Console.WriteLine("Apply luxury tax."); }

Это похоже на изучение полей записи для принятия решений о действиях.


6. Позиционные образцы

Деконструирование объектов или кортежей для сопоставления отдельных компонентов.

Пример:

(Point x, Point y) = (new(0, 0), new(1, 1));  string status = (x, y) switch {     (0, 0) => "At origin",     (_, _) => "Somewhere else" };

Отлично работает при моделировании координат, интервалов или систем сеток.


7. Образец var 

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

Пример:

if (GetData() is var data && data.Length > 0) {     Console.WriteLine("Data retrieved!"); }

Это удобно при выполнении проверок или преобразований на лету.


8. Образец сброса 

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

Пример:

string GetDayStatus(DayOfWeek? day) => day switch {     DayOfWeek.Monday => "Start of week",     DayOfWeek.Friday => "Almost weekend",     _ => "Another day" };

Полезно для охватывающих всё fallback.


9. Образцы списков (C# 11+) 

Позволяют проверять последовательности (например, массивы/списки) со вложенными образцами.

Примеры:

int[] ratings = { 5, 4, 3 };  if (ratings is [5, .., >= 3]) {     Console.WriteLine("Great feedback!"); }

Также можно извлекать срезы с помощью ...

if (ratings is [_, .. var middle, _]) {     Console.WriteLine($"Middle scores: {string.Join(", ", middle)}"); }

Полезно при валидации структурированных данных, например оценок за экзамены, массивов конфигураций и так далее.


Подведём итог 

Тип образца

Сценарий использования

Объявление/тип

Проверка и приведение типов

Константа

Сопоставление с точным значением

Относительный

Сравнение с интервалом

Логический

Сложные комбинации

Свойство

Сопоставление значений свойств объекта

Позиционный

Сопоставление на основании деконструкции

Var

Извлечение значения

Сброс

Сопоставление с чем угодно без учёта значения

Список

Сопоставление массивов/списков и подпоследовательностей


Когда следует использовать сопоставление с образцом? 

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

  • Вы работаете с разнородными типами (например, с параметрами object).

  • Необходимо избежать длинных проверок на null.

  • Нужно повысить читаемость условных операторов.

  • Выполняется обработка сложной логики ветвления (например, преобразования ответов API).

В заключение 

Чем больше я практиковался, тем сильнее осознавал, что сопоставление с образцом в C# — это не просто синтаксический трюк, а смена образа мышления.

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

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

Готовы двигаться дальше? Попробуйте отрефакторить один из своих недавних блоков кода, переполненных switch или if, превратив их в изящную логику на основе образцов.


ссылка на оригинал статьи https://habr.com/ru/articles/907264/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *