AYUDA .NET

Expresiones de correspondencia de patrones en C# (Cómo funciona para desarrolladores)

Actualizado 26 de marzo, 2024
Compartir:

Introducción

La concordancia de patrones en C# es una potente función que se introdujo en C# 7.0 y que se ha ampliado en versiones posteriores. Permite a los desarrolladores escribir código más conciso y expresivo cuando se trata de sentencias condicionales, comprobación de tipos y deconstrucción de objetos.

Las expresiones de concordancia de patrones proporcionan una forma flexible e intuitiva de comparar valores con patrones y ejecutar los bloques de código correspondientes. En este artículo, exploraremos las complejidades de las expresiones de concordancia de patrones en C#, incluyendo sintaxis, casos de uso y ejemplos de código. Al final del artículo también exploraremos un poco sobre IronPDF de Iron Software para generar un documento PDF sobre la marcha en aplicaciones C#.

Ventajas de la concordancia de patrones en C#

La concordancia de patrones en código C# presenta una plétora de ventajas:

  • Mayor legibilidad: La concordancia de patrones simplifica la lógica condicional compleja, haciendo que su código sea más fácil de entender y seguir tanto para usted como para otros desarrolladores.
  • Reducción de líneas de código: Al condensar intrincadas sentencias condicionales en patrones concisos, la concordancia de patrones ayuda a racionalizar su base de código, dando lugar a menos líneas de código y a una implementación más sucinta.
  • Mayor facilidad de mantenimiento: La claridad que ofrece la concordancia de patrones facilita el mantenimiento y la depuración del código. Con los patrones claramente delineados, resulta más sencillo identificar y modificar bloques lógicos específicos según sea necesario sin afectar al resto de la base de código.
  • Algoritmos más expresivos: La concordancia de patrones permite a los desarrolladores expresar algoritmos de forma más natural e intuitiva. Al alinear las estructuras del código con los paradigmas de resolución de problemas, la concordancia de patrones facilita la creación de algoritmos que se asemejan mucho a sus modelos conceptuales.

Tipos de concordancia de patrones en C#

La concordancia de patrones es compatible con las siguientes expresiones:

  • es expresión
  • sentencias switch
  • expresiones de conmutación

    Se pueden utilizar los siguientes patrones para que coincidan con las construcciones:

Patrones de declaraciones y tipos

Los patrones de declaración y de tipo son herramientas esenciales en C# para comprobar la compatibilidad de los tipos de expresión en tiempo de ejecución con los tipos dados. Con los patrones de declaración, puede comprobar la compatibilidad y declarar una nueva variable local simultáneamente. Considere el siguiente ejemplo:

object greeting = "Iron Software is Awesome!";
if (greeting is string message)
{
    Console.WriteLine(message.ToLower());  //  salida: Iron Software es impresionante.
}
object greeting = "Iron Software is Awesome!";
if (greeting is string message)
{
    Console.WriteLine(message.ToLower());  //  salida: Iron Software es impresionante.
}
Dim greeting As Object = "Iron Software is Awesome!"
Dim tempVar As Boolean = TypeOf greeting Is String
Dim message As String = If(tempVar, DirectCast(greeting, String), Nothing)
If tempVar Then
	Console.WriteLine(message.ToLower()) '  salida: Iron Software es impresionante.
End If
VB   C#

Aquí, el patrón de declaración garantiza que si la expresión saludo coincide con el tipo cadena, se asigne a la variable mensaje, permitiendo las operaciones posteriores.

Si se cumple alguna de las siguientes condiciones, el modelo de declaración es válido:

  • El tipo en tiempo de ejecución de la expresión es T.
  • El tipo en tiempo de ejecución de la expresión deriva de T, implementa la interfaz T o puede convertirse implícitamente a T.
  • El tipo en tiempo de ejecución de la expresión es un tipo de valor anulable con el tipo subyacente T.
  • Existe una conversión boxing o unboxing del tipo en tiempo de ejecución de la expresión al tipo T.

    Considere el siguiente ejemplo que demuestra las condiciones anteriores:

int? nullableX = 8;
int y = 45;
object boxedy = y;
if (nullableX is int a && boxedy is int b)
{
    Console.WriteLine(a + b);  //  salida: 53
}
int? nullableX = 8;
int y = 45;
object boxedy = y;
if (nullableX is int a && boxedy is int b)
{
    Console.WriteLine(a + b);  //  salida: 53
}
Dim nullableX? As Integer = 8
Dim y As Integer = 45
Dim boxedy As Object = y
Dim tempVar As Boolean = TypeOf boxedy Is Integer
Dim b As Integer = If(tempVar, DirectCast(boxedy, Integer), Nothing)
Dim tempVar2 As Boolean = TypeOf nullableX Is Integer
Dim a As Integer = If(tempVar2, CInt(nullableX), Nothing)
If tempVar2 AndAlso tempVar Then
	Console.WriteLine(a + b) '  salida: 53
End If
VB   C#

Aquí, nullableX coincide con el patrón porque es un tipo de valor anulable con el tipo subyacente int, y boxedy coincide porque puede ser unboxed a int.

Cuando sólo necesite comprobar el tipo de expresión sin declarar una nueva variable, puede utilizar el descarte _, como se ve en el ejemplo siguiente:

public static decimal CalculateToll(this Vehicle vehicle) => vehicle switch
{
    bus _ => 4.00m,
    motor _ => 8.50m,
    null => throw new ArgumentNullException(nameof(vehicle)),
    _ => throw new ArgumentException("Unknown type of a vehicle", nameof(vehicle)),
};
public static decimal CalculateToll(this Vehicle vehicle) => vehicle switch
{
    bus _ => 4.00m,
    motor _ => 8.50m,
    null => throw new ArgumentNullException(nameof(vehicle)),
    _ => throw new ArgumentException("Unknown type of a vehicle", nameof(vehicle)),
};
'INSTANT VB TODO TASK: The following 'switch expression' was not converted by Instant VB:
'public static decimal CalculateToll(this Vehicle vehicle) => vehicle switch
'{
'	bus _ => 4.00m,
'	motor _ => 8.50m,
'	null => throw new ArgumentNullException(nameof(vehicle)),
'	_ => throw new ArgumentException("Unknown type of a vehicle", nameof(vehicle)),
'};
VB   C#

En este fragmento, el _ sirve como marcador de posición para cualquier tipo que coincida con Vehículo.

Tanto los patrones de declaración como los de tipo garantizan que las expresiones no sean nulas antes de la coincidencia de patrones. Puede comprobar si no es nulo utilizando un patrón de constante nulo negado, como se ilustra a continuación:

if (inputVal is not null)
{
    //  ...
}
if (inputVal is not null)
{
    //  ...
}
If inputVal IsNot Nothing Then
	'  ...
End If
VB   C#

Esta negación garantiza que la entrada no es nula antes de proceder con otras operaciones.

Si aprovecha los patrones de declaraciones y tipos en su código C#, podrá mejorar la legibilidad, reducir las líneas de código y expresar algoritmos de forma más eficaz. Estos patrones proporcionan una forma concisa y expresiva de manejar la lógica basada en tipos y mejorar la capacidad de mantenimiento de su código base.

Patrón constante

Los patrones constantes sirven para verificar si el resultado de una expresión coincide con un valor constante específico. Considere el siguiente ejemplo:

public static decimal GetGroupTicketPrice(int visitorCount) => visitorCount switch
{
    1 => 2.0m,
    2 => 10.0m,
    3 => 25.0m,
    4 => 60.0m,
    0 => 0.0m,
    _ => throw new ArgumentException($"Not supported number of visitors: {visitorCount}", nameof(visitorCount)),
};
public static decimal GetGroupTicketPrice(int visitorCount) => visitorCount switch
{
    1 => 2.0m,
    2 => 10.0m,
    3 => 25.0m,
    4 => 60.0m,
    0 => 0.0m,
    _ => throw new ArgumentException($"Not supported number of visitors: {visitorCount}", nameof(visitorCount)),
};
Dim tempVar As Decimal
Select Case visitorCount
	Case 1
		tempVar = 2.0D
	Case 2
		tempVar = 10.0D
	Case 3
		tempVar = 25.0D
	Case 4
		tempVar = 60.0D
	Case 0
		tempVar = 0.0D
	Case Else
'INSTANT VB TODO TASK: Throw expressions are not converted by Instant VB:
'ORIGINAL LINE: tempVar = throw new ArgumentException(string.Format("Not supported number of visitors: {0}", visitorCount), nameof(visitorCount));
		tempVar = throw New ArgumentException($"Not supported number of visitors: {visitorCount}", NameOf(visitorCount))
End Select
'INSTANT VB TODO TASK: Local functions are not converted by Instant VB:
'public static decimal GetGroupTicketPrice(int visitorCount)
'{
'	Return tempVar;
'}
VB   C#

Aquí, los patrones constantes comprueban si visitorCount coincide con alguno de los valores constantes especificados y devuelven los precios de las entradas correspondientes.

En un patrón constante, puede emplear varios tipos de expresiones constantes, como:

  1. Literales numéricos enteros o de coma flotante.
  2. Personajes.
  3. Literales de cadena.
  4. Valores booleanos (verdadero o falso).
  5. Valores Enum.
  6. El nombre de un campo const o local declarado.
  7. nulo.

    Una expresión de tipo Spano ReadOnlySpanpuede coincidir con cadenas constantes.

    Para comprobar si es nulo, utilice un patrón constante como éste:

if (inputVal is null)
{
    return;
}
if (inputVal is null)
{
    return;
}
If inputVal Is Nothing Then
	Return
End If
VB   C#

Aquí, el patrón se asegura de que la entrada es nula antes de proceder con otras operaciones.

También puede utilizar un patrón de constante nula negada para determinar valores no nulos:

if (inputVal is not null)
{
    //  ...
}
if (inputVal is not null)
{
    //  ...
}
If inputVal IsNot Nothing Then
	'  ...
End If
VB   C#

Este patrón verifica que la entrada no es nula, lo que permite realizar operaciones posteriores de forma segura.

Al incorporar patrones de constantes en su código C#, puede manejar con eficacia situaciones en las que es necesario hacer coincidir valores constantes específicos, lo que mejora la claridad y la capacidad de mantenimiento del código.

Patrones relacionales

Los patrones relacionales permiten comparar los resultados de las expresiones con constantes. Considere el siguiente ejemplo:

Console.WriteLine(Classify(20));  //  salida: Demasiado alta
Console.WriteLine(Classify(double.NaN));  //  salida: Desconocido
Console.WriteLine(Classify(4));  //  salida: Aceptable
static string Classify(double measurement) => measurement switch
{
    < -4.0 => "Too low",
    > 10.0 => "Too high",
    double.NaN => "Unknown",
    _ => "Acceptable",
};
Console.WriteLine(Classify(20));  //  salida: Demasiado alta
Console.WriteLine(Classify(double.NaN));  //  salida: Desconocido
Console.WriteLine(Classify(4));  //  salida: Aceptable
static string Classify(double measurement) => measurement switch
{
    < -4.0 => "Too low",
    > 10.0 => "Too high",
    double.NaN => "Unknown",
    _ => "Acceptable",
};
Console.WriteLine(Classify(20)) '  salida: Demasiado alta
Console.WriteLine(Classify(Double.NaN)) '  salida: Desconocido
Console.WriteLine(Classify(4)) '  salida: Aceptable
'INSTANT VB TODO TASK: The following 'switch expression' was not converted by Instant VB:
'static string Classify(double measurement) => measurement switch
'{
'	< -4.0 => "Too low",
'	> 10.0 => "Too high",
'	double.NaN => "Unknown",
'	_ => "Acceptable",
'};
VB   C#

Aquí, los patrones relacionales comparan la medida con umbrales específicos para determinar su clasificación.

La parte derecha de un patrón relacional debe ser una expresión constante, que puede ser de tipo entero, punto flotante, char o enum. Los operadores <, >, <=, o >= pueden utilizarse en el lado izquierdo.

Para hacer coincidir el resultado de una expresión dentro de un rango determinado, emplee un patrón conjuntivo y, como se ilustra a continuación:

Console.WriteLine(GetCalendarSeason(new DateTime(2024, 3, 12)));  //  salida: muelle
Console.WriteLine(GetCalendarSeason(new DateTime(2024, 7, 12)));  //  salida: verano
Console.WriteLine(GetCalendarSeason(new DateTime(2024, 2, 12)));  //  producción: invierno
static string GetCalendarSeason(DateTime date) => date.Month switch
{
    >= 3 and < 6 => "spring",
    >= 6 and < 9 => "summer",
    >= 9 and < 12 => "autumn",
    12 or (>= 1 and < 3) => "winter",
    _ => throw new ArgumentOutOfRangeException(nameof(date), $"Date with unexpected month: {date.Month}."),
};
Console.WriteLine(GetCalendarSeason(new DateTime(2024, 3, 12)));  //  salida: muelle
Console.WriteLine(GetCalendarSeason(new DateTime(2024, 7, 12)));  //  salida: verano
Console.WriteLine(GetCalendarSeason(new DateTime(2024, 2, 12)));  //  producción: invierno
static string GetCalendarSeason(DateTime date) => date.Month switch
{
    >= 3 and < 6 => "spring",
    >= 6 and < 9 => "summer",
    >= 9 and < 12 => "autumn",
    12 or (>= 1 and < 3) => "winter",
    _ => throw new ArgumentOutOfRangeException(nameof(date), $"Date with unexpected month: {date.Month}."),
};
Console.WriteLine(GetCalendarSeason(New DateTime(2024, 3, 12))) '  salida: muelle
Console.WriteLine(GetCalendarSeason(New DateTime(2024, 7, 12))) '  salida: verano
Console.WriteLine(GetCalendarSeason(New DateTime(2024, 2, 12))) '  producción: invierno
'INSTANT VB TODO TASK: The following 'switch expression' was not converted by Instant VB:
'static string GetCalendarSeason(DateTime date) => date.Month switch
'{
'	>= 3 and < 6 => "spring",
'	>= 6 and < 9 => "summer",
'	>= 9 and < 12 => "autumn",
'	12 or (>= 1 and < 3) => "winter",
'	_ => throw new ArgumentOutOfRangeException(nameof(date), $"Date with unexpected month: {date.Month}."),
'};
VB   C#

Este extracto describe cómo se utiliza el patrón conjuntivo "y" para determinar la estación del calendario basándose en el mes que cae dentro de unos rangos específicos. También menciona que los patrones relacionales proporcionan un medio conciso y expresivo para comparar resultados de expresiones con constantes, mejorando así la claridad y la mantenibilidad del código.

Patrón de descarte

El patrón de descarte, denotado por _, sirve para coincidir con cualquier expresión, incluyendo null. Tomemos el siguiente ejemplo:

Console.WriteLine(GetDiscountInPercent(DayOfWeek.Friday));  //  salida: 5.0
Console.WriteLine(GetDiscountInPercent(null));  //  salida: 0.0
Console.WriteLine(GetDiscountInPercent((DayOfWeek)10));  //  salida: 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,
};
Console.WriteLine(GetDiscountInPercent(DayOfWeek.Friday));  //  salida: 5.0
Console.WriteLine(GetDiscountInPercent(null));  //  salida: 0.0
Console.WriteLine(GetDiscountInPercent((DayOfWeek)10));  //  salida: 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,
};
Console.WriteLine(GetDiscountInPercent(DayOfWeek.Friday)) '  salida: 5.0
Console.WriteLine(GetDiscountInPercent(Nothing)) '  salida: 0.0
Console.WriteLine(GetDiscountInPercent(CType(10, DayOfWeek))) '  salida: 0.0
Dim tempVar As Decimal
Select Case dayOfWeek
	Case DayOfWeek.Monday
		tempVar = 0.5D
	Case DayOfWeek.Tuesday
		tempVar = 12.5D
	Case DayOfWeek.Wednesday
		tempVar = 7.5D
	Case DayOfWeek.Thursday
		tempVar = 12.5D
	Case DayOfWeek.Friday
		tempVar = 5.0D
	Case DayOfWeek.Saturday
		tempVar = 2.5D
	Case DayOfWeek.Sunday
		tempVar = 2.0D
	Case Else
		tempVar = 0.0D
End Select
'INSTANT VB TODO TASK: Local functions are not converted by Instant VB:
'static decimal GetDiscountInPercent(System.Nullable(Of DayOfWeek) dayOfWeek)
'{
'	Return tempVar;
'}
VB   C#

En el patrón de descarte del ejemplo anterior se manejan todos los valores de entrada posibles. Todos los días de la semana se manejan y representan el valor por defecto. Con esto se manejan todos los valores posibles. El patrón de descarte no puede utilizarse como patrón en una expresión is o en una sentencia switch. En tales casos, puede emplear un patrón var con un descarte, como var _, para que coincida con cualquier expresión. Sin embargo, se permite un patrón de descarte en una expresión de conmutación. Para más detalles, consulte la sección Patrón de descarte de la nota de propuesta de función.

Patrones lógicos

Los patrones lógicos en C# ofrecen potentes herramientas para la concordancia de patrones, incluidas la negación, la conjunción y la disyunción, que permiten condiciones de concordancia más flexibles y expresivas.

Negación (no patrón)

El patrón de negación, representado por 'not', coincide con una expresión cuando el patrón negado no coincide con la expresión. Esto resulta especialmente útil para comprobar si una expresión no es nula, como se muestra a continuación:

if (input is not null)
{
    //  ...
}
if (input is not null)
{
    //  ...
}
If input IsNot Nothing Then
	'  ...
End If
VB   C#

Aquí, el bloque de código se ejecuta si la entrada no es nula.

Conjuntivo (y patrón)

El patrón conjuntivo, que utiliza la palabra clave "and", coincide con una expresión cuando ambos patrones coinciden con la expresión. Esto permite combinar varias condiciones, como se ilustra en el siguiente ejemplo:

Console.WriteLine(Classify(13));    //  salida: Alta
Console.WriteLine(Classify(-100));  //  salida: Demasiado baja
Console.WriteLine(Classify(5.7));   //  salida: Aceptable
static string Classify(double measurement) => measurement switch
{
    < -40.0 => "Too low",
    >= -40.0 and < 0 => "Low",
    >= 0 and < 10.0 => "Acceptable",
    >= 10.0 and < 20.0 => "High",
    >= 20.0 => "Too high",
    double.NaN => "Unknown",
};
Console.WriteLine(Classify(13));    //  salida: Alta
Console.WriteLine(Classify(-100));  //  salida: Demasiado baja
Console.WriteLine(Classify(5.7));   //  salida: Aceptable
static string Classify(double measurement) => measurement switch
{
    < -40.0 => "Too low",
    >= -40.0 and < 0 => "Low",
    >= 0 and < 10.0 => "Acceptable",
    >= 10.0 and < 20.0 => "High",
    >= 20.0 => "Too high",
    double.NaN => "Unknown",
};
Console.WriteLine(Classify(13)) '  salida: Alta
Console.WriteLine(Classify(-100)) '  salida: Demasiado baja
Console.WriteLine(Classify(5.7)) '  salida: Aceptable
'INSTANT VB TODO TASK: The following 'switch expression' was not converted by Instant VB:
'static string Classify(double measurement) => measurement switch
'{
'	< -40.0 => "Too low",
'	>= -40.0 and < 0 => "Low",
'	>= 0 and < 10.0 => "Acceptable",
'	>= 10.0 and < 20.0 => "High",
'	>= 20.0 => "Too high",
'	double.NaN => "Unknown",
'};
VB   C#

En este ejemplo, la medida se clasifica en función de su intervalo de valores.

Disyuntiva (o patrón)

El patrón disyuntivo, que utiliza la palabra clave "o", coincide con una expresión cuando cualquiera de los dos patrones coincide con la expresión. Esto permite manejar múltiples condiciones posibles, como se muestra a continuación:

Console.WriteLine(GetCalendarSeason(new DateTime(2021, 1, 19)));  //  producción: invierno
    Console.WriteLine(GetCalendarSeason(new DateTime(2021, 10, 9)));  //  salida: otoño
    Console.WriteLine(GetCalendarSeason(new DateTime(2021, 5, 11)));  //  salida: muelle
    static string GetCalendarSeason(DateTime date) => date.Month switch
    {
        3 or 4 or 5 => "spring",
        6 or 7 or 8 => "summer",
        9 or 10 or 11 => "autumn",
        12 or 1 or 2 => "winter",
        _ => throw new ArgumentOutOfRangeException(nameof(date), $"Date with unexpected month: {date.Month}."),
    };
Console.WriteLine(GetCalendarSeason(new DateTime(2021, 1, 19)));  //  producción: invierno
    Console.WriteLine(GetCalendarSeason(new DateTime(2021, 10, 9)));  //  salida: otoño
    Console.WriteLine(GetCalendarSeason(new DateTime(2021, 5, 11)));  //  salida: muelle
    static string GetCalendarSeason(DateTime date) => date.Month switch
    {
        3 or 4 or 5 => "spring",
        6 or 7 or 8 => "summer",
        9 or 10 or 11 => "autumn",
        12 or 1 or 2 => "winter",
        _ => throw new ArgumentOutOfRangeException(nameof(date), $"Date with unexpected month: {date.Month}."),
    };
Console.WriteLine(GetCalendarSeason(New DateTime(2021, 1, 19))) '  producción: invierno
	Console.WriteLine(GetCalendarSeason(New DateTime(2021, 10, 9))) '  salida: otoño
	Console.WriteLine(GetCalendarSeason(New DateTime(2021, 5, 11))) '  salida: muelle
	Dim tempVar As String
	Select Case [date].Month
		Case 3, 4, 5
			tempVar = "spring"
		Case 6, 7, 8
			tempVar = "summer"
		Case 9, 10, 11
			tempVar = "autumn"
		Case 12, 1, 2
			tempVar = "winter"
		Case Else
'INSTANT VB TODO TASK: Throw expressions are not converted by Instant VB:
'ORIGINAL LINE: tempVar = throw new ArgumentOutOfRangeException(nameof(date), string.Format("Date with unexpected month: {0}.", date.Month));
			tempVar = throw New ArgumentOutOfRangeException(NameOf([date]), $"Date with unexpected month: {[date].Month}.")
	End Select
'INSTANT VB TODO TASK: Local functions are not converted by Instant VB:
'	static string GetCalendarSeason(DateTime @date)
'	{
'		Return tempVar;
'	}
VB   C#

En este caso, la temporada del calendario se determina en función del mes de la fecha facilitada.

Estos combinadores de patrones pueden utilizarse repetidamente para crear condiciones de coincidencia más complejas y precisas, mejorando la flexibilidad y legibilidad de su código.

Patrón de propiedad

El patrón de propiedades permite comparar las propiedades o campos de una expresión con patrones anidados. Un ejemplo de ello puede verse en el siguiente fragmento de código:

static bool IsConferenceDay(DateTime date) => date is { Year: 2020, Month: 5, Day: 19 or 20 or 21 };
static bool IsConferenceDay(DateTime date) => date is { Year: 2020, Month: 5, Day: 19 or 20 or 21 };
Shared Function IsConferenceDay(ByVal [date] As DateTime) As Boolean
'INSTANT VB TODO TASK: The following 'is' operator pattern is not converted by Instant VB:
	Return [date] is { Year: 2020, Month: 5, Day: 19 [or] 20 [or] 21 }
End Function
VB   C#

Aquí, el patrón de propiedades garantiza que la fecha proporcionada se corresponde con uno de los días de conferencia especificados.

También puede incorporar una comprobación de tipo en tiempo de ejecución y una declaración de variable dentro de un patrón de propiedad, como se muestra a continuación:

static string TakeFive(object input) => input switch
{
    string { Length: >= 5 } s => s.Substring(0, 5),
    string s => s,
    ICollection<char> { Count: >= 5 } symbols => new string(symbols.Take(5).ToArray()),
    ICollection<char> symbols => new string(symbols.ToArray()),
    null => throw new ArgumentNullException(nameof(input)),
    _ => throw new ArgumentException("Unsupported input type."),
};
static string TakeFive(object input) => input switch
{
    string { Length: >= 5 } s => s.Substring(0, 5),
    string s => s,
    ICollection<char> { Count: >= 5 } symbols => new string(symbols.Take(5).ToArray()),
    ICollection<char> symbols => new string(symbols.ToArray()),
    null => throw new ArgumentNullException(nameof(input)),
    _ => throw new ArgumentException("Unsupported input type."),
};
'INSTANT VB TODO TASK: The following 'switch expression' was not converted by Instant VB:
'static string TakeFive(object input) => input switch
'{
'	string { Length: >= 5 } s => s.Substring(0, 5),
'	string s => s,
'	ICollection<char> { Count: >= 5 } symbols => new string(symbols.Take(5).ToArray()),
'	ICollection<char> symbols => new string(symbols.ToArray()),
'	null => throw new ArgumentNullException(nameof(input)),
'	_ => throw new ArgumentException("Unsupported input type."),
'};
VB   C#

Aquí, el patrón de propiedades se utiliza para manejar cadenas y colecciones de caracteres, asegurando un manejo adecuado basado en sus propiedades.

Patrón posicional

En C#, el patrón posicional permite deconstruir el resultado de una expresión y comparar los valores resultantes con los patrones anidados correspondientes. Por 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",
};
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",
};
'INSTANT VB WARNING: VB has no equivalent to the C# readonly struct:
'ORIGINAL LINE: public readonly struct Point
Public Structure Point
	Public ReadOnly Property X() As Integer
	Public ReadOnly Property Y() As Integer
	Public Sub New(ByVal x As Integer, ByVal y As Integer)
'INSTANT VB TODO TASK: VB has no equivalent to the C# deconstruction assignments:
		(X, Y) = (x, y)
	End Sub
	Public Sub Deconstruct(<System.Runtime.InteropServices.Out()> ByRef x As Integer, <System.Runtime.InteropServices.Out()> ByRef y As Integer)
'INSTANT VB TODO TASK: VB has no equivalent to the C# deconstruction assignments:
		(x, y) = (X, Y)
	End Sub
End Structure
'INSTANT VB TODO TASK: The following 'switch expression' was not converted by Instant VB:
'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",
'};
VB   C#

En este ejemplo, el patrón posicional se utiliza para clasificar los puntos en función de sus coordenadas.

Además, puede hacer referencia a propiedades o campos anidados dentro de un patrón de propiedades, conocido como patrón de propiedades extendido, introducido en C# 10:

static bool IsAnyEndOnXAxis(Segment segment) =>
    segment is { Start.Y: 0 } or { End.Y: 0 };
static bool IsAnyEndOnXAxis(Segment segment) =>
    segment is { Start.Y: 0 } or { End.Y: 0 };
Shared Function IsAnyEndOnXAxis(ByVal segment As Segment) As Boolean
'INSTANT VB TODO TASK: The following 'is' operator pattern is not converted by Instant VB:
	Return segment is { Start.Y: 0 } [or] { [End].Y: 0 }
End Function
VB   C#

Esta función aumenta la flexibilidad de los patrones de propiedades al permitir el acceso directo a las propiedades anidadas.

Estos patrones proporcionan potentes mecanismos para manejar estructuras de datos complejas y mejorar la legibilidad y expresividad del código.

Patrón Var

Var Pattern le permite coincidir con cualquier tipo. Esto puede ser especialmente útil para capturar resultados intermedios dentro de expresiones booleanas o cuando se requieren múltiples comprobaciones en los guardianes de casos de conmutación.

He aquí un ejemplo que demuestra el uso del patrón var en una expresión booleana:

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();
}
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();
}
Shared Function IsAcceptable(ByVal id As Integer, ByVal absLimit As Integer) As Boolean
	Dim tempVar As Boolean = TypeOf SimulateDataFetch(id) Is var
	Dim results = If(tempVar, CType(SimulateDataFetch(id), var), Nothing)
	Return tempVar AndAlso results.Min() >= -absLimit AndAlso results.Max() <= absLimit
End Function
Shared Function SimulateDataFetch(ByVal id As Integer) As Integer()
	Dim rand = New Random()
	Return Enumerable.Range(start:= 0, count:= 5).Select(Function(s) rand.Next(minValue:= -10, maxValue:= 11)).ToArray()
End Function
VB   C#

En este ejemplo, SimulateDataFetch devuelve un array de enteros, y el patrón is var captura el resultado en la variable results, permitiendo cálculos posteriores basados en sus propiedades.

Además, los patrones var pueden utilizarse dentro de expresiones o sentencias switch para obtener un código más conciso y legible. Aquí hay un ejemplo usando el patrón var en los guardianes del caso switch:

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)));  //  salida: Punto { X = -1, Y = 2 }
    Console.WriteLine(Transform(new Point(5, 2)));  //  salida: Punto { X = 5, Y = -2 }
}
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)));  //  salida: Punto { X = -1, Y = 2 }
    Console.WriteLine(Transform(new Point(5, 2)));  //  salida: Punto { X = 5, Y = -2 }
}
'INSTANT VB TODO TASK: C# 'records' are not converted by Instant VB:
'public record Point(int X, int Y)
'INSTANT VB TODO TASK: The following 'switch expression' was not converted by Instant VB:
'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),
'};
Shared Sub TestTransform()
	Console.WriteLine(Transform(New Point(1, 2))) '  salida: Punto { X = -1, Y = 2 }
	Console.WriteLine(Transform(New Point(5, 2))) '  salida: Punto { X = 5, Y = -2 }
End Sub
VB   C#

En este ejemplo, el patrón var (x, y) captura las coordenadas del punto, permitiendo diferentes transformaciones basadas en sus valores.

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

El patrón var proporciona una forma cómoda de manejar diversos escenarios en los que el tipo específico de expresión no se conoce de antemano, mejorando la claridad y flexibilidad del código.

Presentación de la biblioteca IronPDF

IronPDF es una biblioteca de Iron Software especializada en la generación de documentos PDF. Para empezar lo primero es instalar la librería desde el gestor de paquetes NuGet o desde el gestor de paquetes de Visual Studio

Install-Package IronPdf

La siguiente imagen muestra cómo instalar desde Visual Studio.

Expresiones de correspondencia de patrones en C# (Cómo funciona para los desarrolladores): Figura 1 - Instalación de IronPDF con el gestor de paquetes NuGet

En el siguiente código, veremos cómo podemos generar un simple documento PDF:

namespace IronPatterns;
class Program
{
    static void Main()
    {
        Console.WriteLine("-----------Iron Software-------------");
        var renderer = new ChromePdfRenderer(); //  var patrón
        var content = " <h1> Iron Software is Awesome </h1> Made with IronPDF!";
        //  Patrón de declaración
        int? nullableX = 8;
        int y = 45;
        object boxedy = y;
        content += "<p>Declaration Pattern</p>";
        if (nullableX is int a && boxedy is int b)
        {
            Console.WriteLine(a + b); //  salida: 53
            content += $"<p>Ouput:{(a + b)}</p>";
        }
        //Patrones relacionales
        content += "<p>Relational patterns</p>";
        var season1 = GetCalendarSeason(new DateTime(2024, 2, 25));
        Console.WriteLine(season1);
        content += $"<p>2024, 2, 25:{season1}</p>";
        var season2 = GetCalendarSeason(new DateTime(2024, 5, 25));
        Console.WriteLine(season2);
        content += $"<p>2024, 5, 25:{season1}</p>";
        var season3 = GetCalendarSeason(new DateTime(2024, 7, 25));
        Console.WriteLine(season3);
        content += $"<p>2024, 7, 25:{season1}</p>";
        var pdf = renderer.RenderHtmlAsPdf(content);
        pdf.SaveAs("output.pdf"); //  Guarda nuestro objeto PdfDocument como PDF        
    }
    static string GetCalendarSeason(DateTime date) => date.Month switch
    {
        >= 3 and < 6 => "spring",
        >= 6 and < 9 => "summer",
        >= 9 and < 12 => "autumn",
        12 or (>= 1 and < 3) => "winter",
        _ => throw new ArgumentOutOfRangeException(nameof(date), $"Date with unexpected month: {date.Month}."),
    };
}
namespace IronPatterns;
class Program
{
    static void Main()
    {
        Console.WriteLine("-----------Iron Software-------------");
        var renderer = new ChromePdfRenderer(); //  var patrón
        var content = " <h1> Iron Software is Awesome </h1> Made with IronPDF!";
        //  Patrón de declaración
        int? nullableX = 8;
        int y = 45;
        object boxedy = y;
        content += "<p>Declaration Pattern</p>";
        if (nullableX is int a && boxedy is int b)
        {
            Console.WriteLine(a + b); //  salida: 53
            content += $"<p>Ouput:{(a + b)}</p>";
        }
        //Patrones relacionales
        content += "<p>Relational patterns</p>";
        var season1 = GetCalendarSeason(new DateTime(2024, 2, 25));
        Console.WriteLine(season1);
        content += $"<p>2024, 2, 25:{season1}</p>";
        var season2 = GetCalendarSeason(new DateTime(2024, 5, 25));
        Console.WriteLine(season2);
        content += $"<p>2024, 5, 25:{season1}</p>";
        var season3 = GetCalendarSeason(new DateTime(2024, 7, 25));
        Console.WriteLine(season3);
        content += $"<p>2024, 7, 25:{season1}</p>";
        var pdf = renderer.RenderHtmlAsPdf(content);
        pdf.SaveAs("output.pdf"); //  Guarda nuestro objeto PdfDocument como PDF        
    }
    static string GetCalendarSeason(DateTime date) => date.Month switch
    {
        >= 3 and < 6 => "spring",
        >= 6 and < 9 => "summer",
        >= 9 and < 12 => "autumn",
        12 or (>= 1 and < 3) => "winter",
        _ => throw new ArgumentOutOfRangeException(nameof(date), $"Date with unexpected month: {date.Month}."),
    };
}
Namespace IronPatterns
	Friend Class Program
		Shared Sub Main()
			Console.WriteLine("-----------Iron Software-------------")
			Dim renderer = New ChromePdfRenderer() '  var patrón
			Dim content = " <h1> Iron Software is Awesome </h1> Made with IronPDF!"
			'  Patrón de declaración
			Dim nullableX? As Integer = 8
			Dim y As Integer = 45
			Dim boxedy As Object = y
			content &= "<p>Declaration Pattern</p>"
			Dim tempVar As Boolean = TypeOf boxedy Is Integer
			Dim b As Integer = If(tempVar, DirectCast(boxedy, Integer), Nothing)
			Dim tempVar2 As Boolean = TypeOf nullableX Is Integer
			Dim a As Integer = If(tempVar2, CInt(nullableX), Nothing)
			If tempVar2 AndAlso tempVar Then
				Console.WriteLine(a + b) '  salida: 53
				content &= $"<p>Ouput:{(a + b)}</p>"
			End If
			'Patrones relacionales
			content &= "<p>Relational patterns</p>"
			Dim season1 = GetCalendarSeason(New DateTime(2024, 2, 25))
			Console.WriteLine(season1)
			content &= $"<p>2024, 2, 25:{season1}</p>"
			Dim season2 = GetCalendarSeason(New DateTime(2024, 5, 25))
			Console.WriteLine(season2)
			content &= $"<p>2024, 5, 25:{season1}</p>"
			Dim season3 = GetCalendarSeason(New DateTime(2024, 7, 25))
			Console.WriteLine(season3)
			content &= $"<p>2024, 7, 25:{season1}</p>"
			Dim pdf = renderer.RenderHtmlAsPdf(content)
			pdf.SaveAs("output.pdf") '  Guarda nuestro objeto PdfDocument como PDF
		End Sub
'INSTANT VB TODO TASK: The following 'switch expression' was not converted by Instant VB:
'		static string GetCalendarSeason(DateTime date) => date.Month switch
'		{
'			>= 3 and < 6 => "spring",
'			>= 6 and < 9 => "summer",
'			>= 9 and < 12 => "autumn",
'			12 or (>= 1 and < 3) => "winter",
'			_ => throw new ArgumentOutOfRangeException(nameof(date), $"Date with unexpected month: {date.Month}."),
'		};
	End Class
End Namespace
VB   C#

Salida

Expresiones de correspondencia de patrones en C# (Cómo funciona para los desarrolladores): Figura 2

Detalles del código

Aquí estamos utilizando IronPDF ChromePdfRenderer para guardar la cadena HTML en un documento PDF. La salida se guarda en el documento "output.pdf".

Licencia de prueba

IronPDF puede utilizarse con una licencia de prueba obtenida en aquí. Proporcione un Id. de correo electrónico para generar una clave de licencia que se le enviará a su correo electrónico.

"IronPDF.LicenseKey": "<Your Key>"
"IronPDF.LicenseKey": "<Your Key>"
'INSTANT VB TODO TASK: The following line uses invalid syntax:
'"IronPDF.LicenseKey": "<Your Key>"
VB   C#

Coloque la clave de licencia en el archivo AppSettings.Json como se muestra arriba.

Conclusión

Las expresiones de concordancia de patrones en C# ofrecen una forma potente y flexible de escribir sentencias condicionales, comprobaciones de tipo y deconstrucciones de objetos de forma concisa y legible. Al aprovechar la concordancia de patrones, los desarrolladores pueden mejorar la claridad y la capacidad de mantenimiento de su código, al tiempo que reducen la repetición y la redundancia. Ya se trate de comprobación de tipos, sentencias switch o deconstrucción, las expresiones de concordancia de patrones proporcionan un conjunto de herramientas versátil para abordar una amplia gama de tareas de programación en C#.

En conclusión, dominar las expresiones de concordancia de patrones puede mejorar enormemente sus habilidades de programación en C#, permitiéndole escribir un código más limpio y expresivo que sea más fácil de entender y mantener. También en este artículo vimos sobre IronPDF que puede aprovecharse para generar documentos PDF.

< ANTERIOR
Desarrollo de software .NET (Cómo funciona para los desarrolladores)
SIGUIENTE >
C# Internal (Cómo funciona para los desarrolladores)

¿Listo para empezar? Versión: 2024.7 recién publicada

Descarga gratuita de NuGet Descargas totales: 9,974,197 Ver licencias >
123