Patrones de lista y segmentación

Tip

Este artículo forma parte de la sección Aspectos básicos de los desarrolladores que ya conocen al menos un lenguaje de programación y están aprendiendo C#. Comience con la descripción general de la coincidencia de patrones si no está familiarizado con los patrones. Para consultar todas las reglas sobre tipos compatibles e idiomas, consulte patrones de lista en la referencia del lenguaje.

La forma de una secuencia es el conjunto de propiedades observables que requiere un patrón. Estas propiedades pueden incluir el número de elementos, requisitos escritos para cada elemento o para una secuencia de elementos en su conjunto y valores de marcador en índices específicos. Por ejemplo, una forma podría requerir exactamente dos elementos con "Name" en el índice 0, o podría requerir un primer marcador, un último marcador y una secuencia no vacía entre ellos.

Un patrón de lista describe una forma combinando un requisito de recuento de elementos con patrones anidados en posiciones ordenadas. Solo comprueba los requisitos escritos en el patrón: un subpatrón de elemento prueba su elemento correspondiente, mientras que un patrón de segmento puede permitir o probar una secuencia de elementos no coincidentes. Puede usar estas partes para hacer coincidir una cantidad exacta y los valores del marcador, capturar valores en posiciones fijas, permitir una parte intermedia sin coincidencia o aplicar un patrón anidado a esa parte intermedia.

Elija un patrón de lista cuando el tipo en tiempo de compilación del valor de entrada proporcione una propiedad Length o Count y acceso indizado a los elementos, que permite recuperar un elemento por su posición, como en input[index]. Las matrices, las List<T>cadenas y los intervalos son ejemplos comunes. El compilador determina la idoneidad del tipo declarado en tiempo de compilación de la variable, ya que debe resolver estos miembros necesarios antes de que se ejecute el programa. La IEnumerable<T> interfaz por sí misma proporciona enumeración en lugar de esos miembros, incluso cuando el objeto en tiempo de ejecución es una colección indexable.

Los patrones de lista usan una longitud o un número de elementos y acceso indexado a los elementos en lugar de la enumeración. Para los tipos integrados comunes, la búsqueda de coincidencias puede limitarse a comprobar únicamente las posiciones indicadas por el patrón, en lugar de iterar sobre todos los elementos. El costo de esas operaciones depende del tipo de entrada. La iteración de una colección larga puede tardar tiempo, por lo que se usa un bucle o LINQ cuando la decisión requiere examinar un número arbitrario de elementos en lugar de posiciones específicas.

Hacer coincidir una forma exacta

El método siguiente reconoce un encabezado de dos columnas:

static bool IsHeader(string[] columns) =>
    columns is ["Name", "Score"];

La expresión columns es el patrón de entrada. ["Name", "Score"] contiene dos patrones constantes. Un patrón de lista exacto omite un patrón de segmento, requiere exactamente dos elementos y aplica cada patrón anidado al elemento en el mismo índice. Este patrón describe una forma con un recuento exacto y dos valores de marcador: "Name" en el índice 0 y "Score" en el índice 1. Los patrones de elementos anidados son opcionales: el patrón [] de lista vacía describe y coincide con una secuencia sin elementos.

Elija un patrón de lista cuando el patrón combine un número de elementos con requisitos en posiciones concretas. Si solo importa el número de elementos, un patrón de propiedad Length o Count, como items is { Count: 0 }, expresa esa intención de forma más directa.

Usar un descarte para que coincida con cualquier valor de elemento

El siguiente método obtiene al ganador y al tercer clasificado a partir de un orden de llegada de tres nombres:

static string GetAnnouncements(List<string> finishingOrder) =>
    finishingOrder switch
    {
        [var winner, _, var thirdPlace] =>
            $"Winner: {winner}; third place: {thirdPlace}",
        _ => "A complete three-runner result isn't available"
    };

Los var winner patrones y var thirdPlace declaran una variable. Cuando el patrón de lista coincide, C# asigna el valor del elemento coincidente en esa posición a la variable correspondiente, por lo que el resultado puede usar winner y thirdPlace. El patrón _ de descarte acepta el segundo elemento y descarta su valor. Esta forma requiere exactamente tres elementos y proporciona el significado específico de la primera y tercera posición, pero no requiere valores concretos en ninguna posición.

Elija este formulario cuando las posiciones fijas tengan un significado estable. Use un bucle o LINQ cuando necesite inspeccionar un número arbitrario de elementos, transformar una secuencia, buscar en él o realizar agregaciones.

Permitir los elementos restantes con un patrón de segmentación

En este ejemplo simplificado, una línea de comandos puede comenzar con --verbose y contener otros argumentos y se supone que termina con el nombre del archivo de entrada. El método siguiente reconoce formas con un nombre de archivo en la última posición y captura ese valor:

static string GetInputFile(string[] arguments) =>
    arguments switch
    {
        ["--verbose", .., var fileName] => $"Verbose processing: {fileName}",
        [.., var fileName] => $"Processing: {fileName}",
        [] => "No input file was provided"
    };

El patrón de corte.. permite cero o más elementos restantes entre los patrones del primer y del último elemento. Un patrón de lista puede contener como máximo un patrón de segmento. La primera rama switch define una forma con al menos dos elementos: el marcador "--verbose" en el índice 0, un nombre de archivo en la última posición y cualquier número de argumentos no emparejados entre ambos. El segmento independiente no prueba esos argumentos intermedios. El segundo brazo acepta cualquier forma no vacía y captura su último elemento, mientras que el patrón vacío controla una secuencia sin elementos.

Un segmento puede aparecer al principio, al medio o al final de un patrón de lista. Úselo cuando una secuencia de longitud variable forma parte de la forma, pero solo las posiciones circundantes necesitan pruebas de elementos. Use la iteración normal cuando cada elemento necesite procesarse.

Aplicar un patrón a un segmento

Puede aplicar otro patrón a la parte coincidente con ... El método siguiente comprueba si una matriz comienza con "BEGIN", termina con "END"y tiene al menos un elemento entre ellos:

static bool HasContent(string[] entries) =>
    entries is ["BEGIN", .. { Length: > 0 }, "END"];

El patrón externo requiere primero el marcador "BEGIN" en el índice 0 y "END" en el último índice. A continuación, el patrón { Length: > 0 } de propiedad agrega un requisito para la secuencia coincidente con el segmento: debe contener al menos un elemento. Juntos, estos requisitos describen la forma completa. El patrón no prueba los valores de los elementos dentro del segmento.

Use un subpatrón de segmento solo cuando la parte central necesite una prueba o captura. Si solo importan los elementos de límite, plain .. es más sencillo.

Consulte también