Сопоставление с образцом не является новой возможностью. Оно появилось еще в C# 7 и было улучшено в C# 8. В 9 версии языка появились новые образцы, которые расширяют возможности сопоставлений и делают их более удобными для чтения. |
Минимальная платформа с полной поддержкой: нет ограничений.
Для начала перечислим какие образцы уже поддерживаются:
Как и прежде, образцы могут быть использованы в конструкциях is, switch/case и выражении switch.
Упрощение образца типа
В предыдущих версиях C# в образце типа всегда должен был присутсвовать идентификатор или его подстановка _. Начиная с C# 9 это является не обязательным.
Теперь можно использовать следующий формат записи:
[тип] [опциональный идентификатор новой переменной]
Например:
public class Circle { … }
…
var result = obj switch {
…
Circle => throw new NotSupportedException(),
// Для C# 8 и более ранних версий должно быть:
// Circle _ => throw new NotSupportedException(),
…
}
Образцы соотношения
Эти образцы предназначены для проверки соотношение указанного значения из другого образца с константой. Формат записи:
[операция соотношения] [константа]
, где доступны следующие операции:
- < – меньше;
- <= – меньше или равно;
- => – больше или равно;
- > – больше.
Используя их совместно с другими образцами можно создавать достаточно короткие, но выразительные проверки, например:
public record Point(int X, int Y);
…
bool isPositive = point is { X: > 0, Y: > 0 };
Данное сопоставление вернет true если значения свойств X и Y переменной point больше нуля. Как можно заметить, здесь образец соотношения вложен в образец свойств.
Логические образцы
В C# 9 добавились образцы, которые обеспечивают логические операции между другими образцами:
- and – логическое "и";
- or – логическое "или";
- not – логическое "не";
- круглые скобки ( и ) для указания порядка и удобства чтения кода.
Их использование аналогично обычным логическим операциям. Например, and вернет true только если образцы справа и слева от него будут успешно сопоставлены.
Рассмотрим несколько примеров:
public record Point(int X, int Y);
…
// Проверка на null. Аналог "point != null".
if (point is not null) { … }
// X не должен быть равен 0 или 1.
bool isValidX = point is { X: not 0 and not 1 };
// Y должен быть равен -1 или 1.
bool isValidY = point is { Y: -1 or 1 };
// Или X или Y должны быть равны 0.
bool isOnAxis = point is { X: 0 } or { Y: 0 };
// X и Y не должны быть равны ни 0.
bool isNotOnAxis = point is { X: not 0, Y: not 0 };
// X и Y должны быть внутри заданного для них диапазона.
bool isInside = point is { X: >= 0 and <= 10, Y: >= 0 and <= 5 };
Стоит отметить, что новые логические образцы и образцы соотношения позволяют избегать использования дополнительного условия where в выражении switch. В результате код получается более компактный и удобный для чтения:
var index = point switch {
// Синтаксис C# 8
(var x, var y) when 0 <= x && x <= 10 && 0 <= y && y <= 5 => FindIndex(point),
// Синтаксис C# 9
{ X: >= 0 and <= 10, Y: >= 0 and <= 5 } => FindIndex(point),
_ => -1
};
Особенности логических образцов
and:
- Не может использоваться с двумя образцами типа. Исключение – использование c типами интерфейсов.
obj is Point and Circle // Ошибка
obj is IPoint and ICircle // OK
or:
- При использовании для двух образцов типа исходное значение не может быть присвоено в новую переменную.
obj is Point or Circle shape // Ошибка
obj is Point or Circle // OK
- Не может использоваться в одном образце для двух свойств.
obj is { X: 0 or Y: 0 } // Ошибка
obj is { X: 0 } or { Y: 0 } // OK
- Может быть использован внутри другого образца для перебора значений:
obj is { X: 1 or 2 } // OK