sábado, 21 de enero de 2023

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


Patron var 

Utiliza un patrón var para hacer coincidir cualquier expresión, incluido nulo, y asigna su resultado a una nueva variable local, como muestra el siguiente ejemplo:


static bool IsAcceptable(int id, int absLimit) =>

    SimulateDataFetch(id) is var results 

    && results.Min() >= -absLimit 

    && results.Max() <= absLimit;


static int[] SimulateDataFetch(int id)

{

    var rand = new Random();

    return Enumerable

               .Range(start: 0, count: 5)

               .Select(s => rand.Next(minValue: -10, maxValue: 11))

               .ToArray();

}


Un patrón var es útil cuando necesitamos una variable temporal dentro de una expresión booleana para contener el resultado de cálculos intermedios. También podemos usar un patrón var cuando necesitamos realizar más comprobaciones cuando las mayúsculas y minúsculas protegen una expresión o declaración de cambio, como muestra el siguiente ejemplo:

public record Point(int X, int Y);

static Point Transform(Point point) => point switch

{

    var (x, y) when x < y => new Point(-x, y),

    var (x, y) when x > y => new Point(x, -y),

    var (x, y) => new Point(x, y),

};


static void TestTransform()

{

    Console.WriteLine(Transform(new Point(1, 2)));  // output: Point { X = -1, Y = 2 }

    Console.WriteLine(Transform(new Point(5, 2)));  // output: Point { X = 5, Y = -2 }

}


En el ejemplo anterior, el patrón var (x, y) es equivalente a un patrón posicional (var x, var y).

En un patrón var, el tipo de una variable declarada es el tipo de tiempo de compilación de la expresión que se compara con el patrón.


Patrón descartar 

Utiliza un patrón de descarte _ para hacer coincidir cualquier expresión, incluido nulo, como muestra el siguiente ejemplo:

Console.WriteLine(GetDiscountInPercent(DayOfWeek.Friday));  // output: 5.0

Console.WriteLine(GetDiscountInPercent(null));  // output: 0.0

Console.WriteLine(GetDiscountInPercent((DayOfWeek)10));  // output: 0.0


static decimal GetDiscountInPercent(DayOfWeek? dayOfWeek) => dayOfWeek switch

{

    DayOfWeek.Monday => 0.5m,

    DayOfWeek.Tuesday => 12.5m,

    DayOfWeek.Wednesday => 7.5m,

    DayOfWeek.Thursday => 12.5m,

    DayOfWeek.Friday => 5.0m,

    DayOfWeek.Saturday => 2.5m,

    DayOfWeek.Sunday => 2.0m,

    _ => 0.0m,

};


En el ejemplo anterior, se usa un patrón de descarte para controlar valores nulos y enteros que no tienen el miembro correspondiente de la enumeración DayOfWeek. Eso garantiza que una expresión de cambio en el ejemplo maneje todos los valores de entrada posibles. Si no usa un patrón de descarte en una expresión de cambio y ninguno de los patrones de la expresión coincide con una entrada, el tiempo de ejecución genera una excepción. El compilador genera una advertencia si una expresión de cambio no maneja todos los valores de entrada posibles.

Un patrón de descarte no puede ser un patrón en una expresión is o una declaración de cambio. En esos casos, para hacer coincidir cualquier expresión, podemos usar un patrón var con un descarte: var _.


Patrón entre paréntesis

A partir de C# 9.0, podemos poner paréntesis alrededor de cualquier patrón. Por lo general, hace eso para enfatizar o cambiar la precedencia en patrones lógicos, como muestra el siguiente ejemplo:

if (input is not (float or double))

{

    return;

}

Patrones de lista

A partir de C# 11, puede hacer coincidir una matriz o una lista con una secuencia de patrones, como muestra el siguiente ejemplo:

int[] numbers = { 1, 2, 3 };


Console.WriteLine(numbers is [1, 2, 3]);  // True

Console.WriteLine(numbers is [1, 2, 4]);  // False

Console.WriteLine(numbers is [1, 2, 3, 4]);  // False

Console.WriteLine(numbers is [0 or 1, <= 2, >= 3]);  // True

Como muestra el ejemplo anterior, un patrón de lista coincide cuando cada patrón anidado coincide con el elemento correspondiente de una secuencia de entrada. Puede usar cualquier patrón dentro de un patrón de lista. Para hacer coincidir cualquier elemento, use el patrón de descarte o, si también desea capturar el elemento, el patrón var, como muestra el siguiente ejemplo:

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

if (numbers is [var first, _, _])

{

    Console.WriteLine($"The first element of a three-item list is {first}.");

}

// Output:

// The first element of a three-item list is 1.

Los ejemplos anteriores comparan una secuencia de entrada completa con un patrón de lista. Para hacer coincidir los elementos solo al principio o al final de una secuencia de entrada, podemos usar el patrón de división .. dentro de un patrón de lista, como muestra el siguiente ejemplo:

Console.WriteLine(new[] { 1, 2, 3, 4, 5 } is [> 0, > 0, ..]);  // True

Console.WriteLine(new[] { 1, 1 } is [_, _, ..]);  // True

Console.WriteLine(new[] { 0, 1, 2, 3, 4 } is [> 0, > 0, ..]);  // False

Console.WriteLine(new[] { 1 } is [1, 2, ..]);  // False


Console.WriteLine(new[] { 1, 2, 3, 4 } is [.., > 0, > 0]);  // True

Console.WriteLine(new[] { 2, 4 } is [.., > 0, 2, 4]);  // False

Console.WriteLine(new[] { 2, 4 } is [.., 2, 4]);  // True


Console.WriteLine(new[] { 1, 2, 3, 4 } is [>= 0, .., 2 or 4]);  // True

Console.WriteLine(new[] { 1, 0, 0, 1 } is [1, 0, .., 0, 1]);  // True

Console.WriteLine(new[] { 1, 0, 1 } is [1, 0, .., 0, 1]);  // False


Un patrón de división coincide con cero o más elementos. Puede usar como máximo un patrón de división en un patrón de lista.

También puede anidar un subpatrón dentro de un patrón de división, como muestra el siguiente ejemplo:

void MatchMessage(string message)

{

    var result = message is ['a' or 'A', .. var s, 'a' or 'A']

        ? $"Message {message} matches; inner part is {s}."

        : $"Message {message} doesn't match.";

    Console.WriteLine(result);

}


MatchMessage("aBBA");  // output: Message aBBA matches; inner part is BB.

MatchMessage("apron");  // output: Message apron doesn't match.


void Validate(int[] numbers)

{

    var result = numbers is [< 0, .. { Length: 2 or 4 }, > 0] ? "valid" : "not valid";

    Console.WriteLine(result);

}


Validate(new[] { -1, 0, 1 });  // output: not valid

Validate(new[] { -1, 0, 0, 1 });  // output: valid


No hay comentarios.:

Publicar un comentario