Как стать автором
Обновить

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

Уровень сложностиПростой
Время на прочтение4 мин
Количество просмотров3K
Автор оригинала: Arunkumar Gudelli

За годы своего развития 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, превратив их в изящную логику на основе образцов.

Теги:
Хабы:
Если эта публикация вас вдохновила и вы хотите поддержать автора — не стесняйтесь нажать на кнопку
+22
Комментарии21

Публикации

Работа

Ближайшие события