День семьдесят второй. #CSharp8

Новые функции в C# 8.

3. Продвинутое Сопоставление с Шаблоном

Сопоставление выражения с шаблоном предоставляет инструменты для сравнения по форме связанных, но разных типов данных. В C# 7.0 был представлен синтаксис шаблонов типа и шаблонов констант, используя выражения is и switch.

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

Преимущества

Рекурсивное сопоставление с шаблоном помогает вам разбить структуры данных на компоненты и использовать их в очень удобном и компактном синтаксисе. Несмотря на то, что сопоставление с шаблоном эквивалентно последовательности выражений if-then, оно помогает вам писать код в стиле функционального программирования.

Недостатки

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



В следующем примере шаблон выражения используется для сопоставления структуры с шаблоном:

var point = new 3DPoint(1, 2, 3); //x=1, y=2, z=3  

if (point is 3DPoint(1, var myY, _))

{

// Этот код будет выполнен, только если point.X == 1

// myY – это новая переменная,

// которая будет доступна только в этом блоке

// Третий член объекта игнорируется спецсимволом _

}

Шаблоны свойств

Шаблон свойства позволяет вам сопоставить свойства исследуемого объекта. В следующем примере метод рассчитывает налог с продаж в зависимости от штата (свойство State извлекается из передаваемого объекта типа Address). Расчёт этого налога не является ответственностью класса Address, поскольку он может изменяться гораздо чаще, чем структура адреса:

public static decimal ComputeSalesTax(Address location, decimal salePrice) =>

location switch

{

{ State: "WA" } => salePrice * 0.06M,

{ State: "MN" } => salePrice * 0.075M,

{ State: "MI" } => salePrice * 0.05M,

// ...

_ => 0M

};

Позиционные шаблоны

Некоторые типы включают метод Deconstruct, который деконструирует свойства в отдельные переменные. Когда доступен метод Deconstruct, вы можете использовать позиционные шаблоны для сопоставления свойств с шаблоном. Рассмотрим следующий класс точки с координатами X и Y:

public class Point

{

public int X { get; }

public int Y { get; }

public Point(int x, int y) => (X, Y) = (x, y);

public void Deconstruct(out int x, out int y) =>

(x, y) = (X, Y);

}

Также у нас имеется перечисление, представляющее собой позицию точки в системе координат: неизвестна, в центре, в первом квадратне, во втором квадранте, …, на оси координат:

public enum Quadrant

{

Unknown,

Origin,

One,

Two,

Three,

Four,

OnBorder

}

Следующий метод использует позиционный шаблон для извлечения значений x и y, а также использует условие when для определения квадранта:

static Quadrant GetQuadrant(Point point) => point switch

{

(0, 0) => Quadrant.Origin,

var (x, y) when x > 0 && y > 0 => Quadrant.One,

var (x, y) when x < 0 && y > 0 => Quadrant.Two,

var (x, y) when x < 0 && y < 0 => Quadrant.Three,

var (x, y) when x > 0 && y < 0 => Quadrant.Four,

var (_, _) => Quadrant.OnBorder,

_ => Quadrant.Unknown

};

Шаблон пустого кортежа (_, _) соответствует случаю, когда либо x, либо y равно 0, но не оба. Выражение switch должно либо возвращать значение, либо выбрасывать исключение. Если ни один из вариантов не находит соответствия, выражение switch выбрасывает исключение. Компилятор выдаст предупреждение, если вы не укажете все возможные варианты в выражении switch.



Источники:

-
https://www.c-sharpcorner.com/article/c-sharp-8-features/

-
https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8