Información general sobre la coincidencia de patrones

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#. Si no está familiarizado con la programación, comience primero con los tutoriales de introducción . Los desarrolladores de C# experimentados pueden usar la referencia de patrones para la sintaxis y las reglas completas.

¿Viene de otro idioma? Los patrones de C# cumplen una función similar a la comparación de patrones de Java y a los casos de match de Python. C# usa patrones en is expresiones, switch instrucciones y switch expresiones.

La coincidencia de patrones aplica un patrón a una expresión. Un patrón es una condición para probar la expresión de entrada. La entrada de patrón es esa expresión. C# evalúa la expresión de entrada; el resultado es el valor evaluado. El patrón comprueba si ese valor tiene un tipo determinado, es igual a un valor determinado o tiene una forma determinada. Cuando un patrón coincide, el código puede usar la información aprendida por la prueba, como un tipo más específico o un valor extraído de un objeto.

Puede usar un patrón en tres contextos:

  • A la derecha del operador is.
  • En una etiqueta case de una instrucción switch.
  • En una rama de una expresión switch.

Los patrones suelen ser más claros que una secuencia de instrucciones de comparación porque cada rama describe los datos que controla. Por ejemplo, el método siguiente usa una switch expresión para elegir un mensaje de entrega:

static string GetDeliveryMessage(Delivery? delivery) =>
    delivery switch
    {
        null => "No delivery was scheduled.",
        ExpressDelivery express => $"Express package {express.TrackingCode}",
        StandardDelivery { Days: <= 2 } => "Standard delivery arriving soon",
        _ => "Standard delivery"
    };

Los patrones recursivos tienen sus propias expresiones de entrada. En StandardDelivery { Days: <= 2 }, el patrón externo recibe la expresión delivery. El patrón recursivo <= 2 recibe la Days expresión de propiedad del objeto coincidente StandardDelivery .

La expresión anterior switch es la expresión de entrada. Cada línea dentro de las llaves es un brazo de interruptor. El patrón aparece antes de =>, y el resultado aparece después. C# evalúa la expresión de entrada y, a continuación, selecciona el primer brazo, en orden de texto, cuyos patrones coinciden y cuya protección opcional when es true. La protección opcional when es una condición booleana adicional escrita después del patrón. En el ejemplo anterior se muestran los siguientes patrones:

  • null es un patrón constante. Comprueba si la delivery expresión se evalúa como null.
  • ExpressDelivery express es un patrón de declaración con dos partes. ExpressDelivery es la parte de prueba de tipos. Comprueba si el valor evaluado es un objeto distinto de NULL cuyo tipo de tiempo de ejecución es compatible con ExpressDelivery. express es la designación de variable: declara una variable denominada express y le asigna el objeto coincidente ExpressDelivery .
  • StandardDelivery { Days: <= 2 } comienza con una prueba de tipo. StandardDelivery comprueba si el valor evaluado es un objeto distinto de NULL de ese tipo. Las llaves contienen un patrón de propiedades. Days asigna a la propiedad que se va a inspeccionar, por lo que la Days expresión de propiedad se convierte en la entrada del patrón recursivo. La <= 2 parte es un patrón relacional, que comprueba si el valor evaluado es menor o igual que 2.
  • _ (subrayado) es el patrón de descarte. Coincide con cada valor evaluado, incluido null. Dado que las ramas anteriores ya gestionan null, las entregas urgentes y las entregas estándar que llegan en un plazo de dos días, esta rama final gestiona cualquier valor restante.

Un brazo sin protección when no está protegido. Todos los brazos del primer ejemplo no están vigilados. Si una rama anterior sin guarda coincide con todos los valores evaluados con los que podría coincidir una rama posterior, la rama posterior queda subsumida. Un patrón de subsumado es uno en el que cada valor de entrada posible que coincida ya estaba coincidente con un brazo de conmutador anterior. Nunca puede coincidir, por lo que el compilador notifica un error. El brazo de descarte (_) debe ser el último porque coincide con cada expresión de entrada. Un brazo protegido no subsume un brazo posterior basado en su patrón solo porque la guardia podría ser false.

Una expresión switch es exhaustiva cuando sus brazos controlan cada expresión de entrada posible. El primer ejemplo es exhaustivo porque su último brazo de descarte abarca cualquier caso con el que no coincidan los brazos anteriores. El compilador advierte cuando detecta un posible valor de entrada que no maneja ninguna rama. El compilador no puede demostrar exhaustivamente cada combinación de patrones, pero este diagnóstico le ayuda a escribir código de coincidencia de patrones correcto. Para consultar reglas detalladas sobre coincidencia, inclusión y exhaustividad, consulte la referencia sobre patrones.

Prueba de una condición con is

Use el is operador cuando necesite una prueba booleana. El código siguiente evalúa la delivery expresión y aplica el patrón ExpressDelivery expressde declaración . La parte del tipo coincide cuando el valor evaluado no es NULL y su tipo de tiempo de ejecución es compatible con ExpressDelivery. Cuando el patrón coincide, su designación de variable declara express:

static void PrintTrackingCode(Delivery delivery)
{
    if (delivery is ExpressDelivery express)
    {
        Console.WriteLine($"Track express package {express.TrackingCode}");
    }
}

El compilador realiza un seguimiento de si se ha asignado una variable local antes de que el código lo lea. Este seguimiento se denomina asignación definitiva. Dentro del if bloque , la condición solo puede ser true cuando el patrón asignó el objeto coincidente a express. Por lo tanto, el compilador sabe que express está asignado definitivamente allí. El código puede usar su TrackingCode propiedad de forma segura. No necesitas hacer una conversión aparte. Si solo necesita la prueba de tipos y no necesita declarar una variable, use un patrón de tipo, como delivery is ExpressDelivery.

Use is null o is not null para comprobaciones nulas. Estos patrones no llaman a un operador != o == definido por el usuario.

static void PrintPackageStatus(Delivery? delivery)
{
    if (delivery is null)
    {
        Console.WriteLine("No package is available.");
    }
    else
    {
        Console.WriteLine("A package is ready to track.");
    }
}

Para obtener más instrucciones de seguridad nula, consulte Tipos de referencia que aceptan valores NULL.

Elegir entre una instrucción y una expresión

Los patrones funcionan con ambas formas de switch:

  • Use una switch instrucción cuando cada coincidencia ejecute una o varias instrucciones.
  • Use una switch expresión cuando cada coincidencia debe generar un valor.

La siguiente instrucción switch indica una actualización sobre la entrega. La rama de entrega urgente escribe dos mensajes, por lo que una sentencia encaja de forma natural:

static void PrintDeliveryUpdate(Delivery? delivery)
{
    switch (delivery)
    {
        case null:
            Console.WriteLine("No delivery was scheduled.");
            break;
        case ExpressDelivery express:
            Console.WriteLine($"Express delivery {express.TrackingCode} is ready.");
            Console.WriteLine("Notify the priority desk.");
            break;
        case StandardDelivery standard:
            Console.WriteLine($"Standard delivery arrives in {standard.Days} days.");
            break;
        default:
            Console.WriteLine("Another delivery type is scheduled.");
            break;
    }
}

Cada case aplica un patrón a la expresión delivery. La sección de coincidencia puede ejecutar cualquier cantidad de instrucciones antes de que break salga del switch. La sección default se encarga de todo lo que no cubren los casos anteriores.

La siguiente expresión switch reemplaza una if / else if cadena que asigna un resultado:

static string GetStatusMessage(StandardDelivery delivery) =>
    delivery.Days switch
    {
        0 => "Delivered today",
        1 => "Arriving tomorrow",
        <= 3 => "Arriving soon",
        _ => "In transit"
    };

Una expresión switch es concisa porque cada brazo tiene el mismo propósito: generar el valor devuelto. Use una instrucción switch cuando las ramas realicen acciones y use una expresión switch cuando las ramas calculen un resultado.

Categorías de patrones

C# incluye patrones para tipos comunes de pruebas de datos:

Categoría de patrón Qué prueba
Declaración, constante y var patrones Un tipo en tiempo de ejecución, un valor constante específico o cualquier valor que desee capturar
Patrones de tipo Un tipo en tiempo de ejecución sin declarar una variable
Patrones posicionales y de propiedad Propiedades, campos o valores desestructurados
Patrones relacionales y lógicos Comparaciones y combinaciones como and, ory not
Patrones de lista Valores y forma de una lista o matriz
Descartar patrones y descartes Cualquier valor restante o un valor que el código omita intencionadamente

Los artículos Aspectos básicos vinculados en la tabla proporcionan cobertura centrada de las categorías documentadas actualmente en esta sección. Para obtener una sintaxis completa y ejemplos para todas las categorías de patrones, consulte la referencia de patrones.

Consulte también