Pattern matching фактически выполняет сопоставление некоторого значения с некоторым шаблоном. И если сопоставление прошло успешно, то выполняются определенные действия. Язык C# позволяет выполнять различные типы сопоставлений.
Паттерн типов или type pattern позволяет проверить некоторое значение на соответствие некоторому типу:
значение is тип переменная_типа
Например, у нас есть следующие классы:
class Employee { public virtual void Work() => Console.WriteLine("Employee works"); } class Manager : Employee { public override void Work() => Console.WriteLine("Manager works"); public bool IsOnVacation { get; set; } }
Класс Employee представляет работника, а класс Manager - менеджера. Оба класса реализуют метод Work. Кроме того, класс Manager определяет свойство IsOnVacation.
С помощью паттерна типов проверим, представляет ли объект Employee класс Manager:
Employee tom = new Manager(); UseEmployee(tom); // Manager works void UseEmployee(Employee emp) { if (emp is Manager manager && manager.IsOnVacation == false) { manager.Work(); } else { Console.WriteLine("Преобразование не допустимо"); } }
Здесь в методе UseEmployee значение emp
сопоставляется с типом Manager. То есть в данном случае в качестве шаблона выступает тип Manager.
Если сопоставление прошло успешно (то есть значение emp представляет тип Manager), в переменной manager оказывается объект emp.
И далее мы можем вызвать у него методы и свойства.
Также мы можем использовать constant pattern - сопоставление с некоторой константой:
var message = "hello"; // проверяем, соответствует ли значение message строке "hello" if (message is "hello") { Console.WriteLine("hello"); }
Подобным образом, например, можно проверить значение на null:
Employee? bob = new Employee(); Employee? tom = null; UseEmployee(bob); UseEmployee(tom); void UseEmployee(Employee? emp) { if (emp is not null) emp.Work(); }
Кроме конструкции if сопоставление паттернов может применяться в конструкции switch:
Employee bob = new Employee(); Employee tom = new Manager(); UseEmployee(tom); // Manager works UseEmployee(bob); // Object is not manager void UseEmployee(Employee? emp) { switch (emp) { case Manager manager: manager.Work(); break; case null: Console.WriteLine("Object is null"); break; default: Console.WriteLine("Object is not manager"); break; } }
С помощью выражения when можно вводить дополнительные условия в конструкцию case:
Employee bob = new Manager() { IsOnVacation = true }; Employee tom = new Manager() { IsOnVacation = false }; UseEmployee(tom); // Manager works UseEmployee(bob); // Employee does not work void UseEmployee(Employee? emp) { switch (emp) { case Manager manager when !manager.IsOnVacation: manager.Work(); break; case null: Console.WriteLine("Employee is null"); break; default: Console.WriteLine("Employee does not work"); break; } }
В этом случае опять же преобразуем объект emp в объект типа Manager и в случае удачного преобразования смотрим на значение свойства IsOnVacation: если оно равно false, то выполняется данный блок case.