miércoles, 18 de enero de 2023

Pattern matching: las expresiones is y switch, y los operadores and, or y not en C# parte 4


Patrón posicional

Utiliza un patrón posicional para deconstruir un resultado de expresión y hacer coincidir los valores resultantes con los patrones anidados correspondientes, como muestra el siguiente ejemplo:

public readonly struct 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);

}


static string Classify(Point point) => point switch

{

    (0, 0) => "Origin",

    (1, 0) => "positive X basis end",

    (0, 1) => "positive Y basis end",

    _ => "Just a point",

};

En el ejemplo anterior, el tipo de una expresión contiene el método Deconstruct, que se utiliza para deconstruir el resultado de una expresión. También puede hacer coincidir expresiones de tipos de tupla con patrones posicionales. De esa manera, puede hacer coincidir varias entradas con varios patrones, como muestra el siguiente ejemplo:

static decimal GetGroupTicketPriceDiscount(int groupSize, DateTime visitDate)

    => (groupSize, visitDate.DayOfWeek) switch

    {

        (<= 0, _) => throw new ArgumentException("Group size must be positive."),

        (_, DayOfWeek.Saturday or DayOfWeek.Sunday) => 0.0m,

        (>= 5 and < 10, DayOfWeek.Monday) => 20.0m,

        (>= 10, DayOfWeek.Monday) => 30.0m,

        (>= 5 and < 10, _) => 12.0m,

        (>= 10, _) => 15.0m,

        _ => 0.0m,

    };

El ejemplo anterior usa patrones relacionales y lógicos, que están disponibles en C# 9.0 y versiones posteriores.

Se puede usar los nombres de los elementos de tupla y los parámetros de Deconstrucción en un patrón posicional, como muestra el siguiente ejemplo:

var numbers = new List<int> { 1, 2, 3 };

if (SumAndCount(numbers) is (Sum: var sum, Count: > 0))

{

    Console.WriteLine($"Sum of [{string.Join(" ", numbers)}] is {sum}");  // output: Sum of [1 2 3] is 6

}


static (double Sum, int Count) SumAndCount(IEnumerable<int> numbers)

{

    int sum = 0;

    int count = 0;

    foreach (int number in numbers)

    {

        sum += number;

        count++;

    }

    return (sum, count);

}


También puede extender un patrón posicional de cualquiera de las siguientes maneras:

  • Agregue una verificación de tipo en tiempo de ejecución y una declaración de variable, como muestra el siguiente ejemplo:

public record Point2D(int X, int Y);

public record Point3D(int X, int Y, int Z);


static string PrintIfAllCoordinatesArePositive(object point) => point switch

{

    Point2D (> 0, > 0) p => p.ToString(),

    Point3D (> 0, > 0, > 0) p => p.ToString(),

    _ => string.Empty,

};

El ejemplo anterior usa registros posicionales que proporcionan implícitamente el método Deconstruct.

  • Se puede utilizar un patrón de propiedad dentro de un patrón posicional, como muestra el siguiente ejemplo:


public record WeightedPoint(int X, int Y)

{

    public double Weight { get; set; }

}


static bool IsInDomain(WeightedPoint point) => point is (>= 0, >= 0) { Weight: >= 0.0 };


  • Y Tambien se puede combinar los dos usos anteriores, como muestra el siguiente ejemplo:


if (input is WeightedPoint (> 0, > 0) { Weight: > 0.0 } p)

{

    // ..

}


Un patrón posicional es un patrón recursivo. Es decir, puede utilizar cualquier patrón como patrón anidado.


No hay comentarios.:

Publicar un comentario