Capítulo 03: Estruturas Condicionais, Switch Expressions e Pattern Matching

Especialização em Sistemas com C# • C# 12 & .NET 8 • POO Moderna, LINQ, Concorrência e Arquitetura Corporativa


🗺️ Mapa Conceitual do Sistema de Pattern Matching no C# Moderno

flowchart TD
    Entrada["Dado de Entrada para Decisão"] --> Paradigmas["Formas de Casamento de Padrões"]

    subgraph PATTERNS["Padrões do C# 9 / 10 / 11 / 12"]
        TypePattern["Type Pattern: obj is string s"]
        Relational["Relational Patterns: x is >= 0 and <= 100"]
        Property["Property Patterns: { Status: 'OK', Codigo: 200 }"]
        Positional["Positional Patterns: (x, y) is (0, 0)"]
        ListPattern["List Patterns (C# 11): [1, .., var ultimo]"]
    end

    Paradigmas --> PATTERNS
    PATTERNS --> SwitchExpr["Switch Expressions (alvo switch { padrao => resultado })"]
    SwitchExpr --> JumpTable["Otimização JIT: Jump Tables e Saltos Condicionais Mínimos"]

    style Entrada fill:#e1f5fe,stroke:#03a9f4,stroke-width:2px
    style PATTERNS fill:#ede7f6,stroke:#7e57c2,stroke-width:2px
    style SwitchExpr fill:#e8f5e9,stroke:#4caf50,stroke-width:2px

🏛️ 1. A Revolução do Pattern Matching: Da Imperatividade à Expressividade Declarativa

Nas versões iniciais do C#, a tomada de decisão dependia de cadeias repetitivas de if / else if com casts explícitos ou de instruções switch rígidas limitadas a constantes inteiras e strings.

Com as versões modernas da linguagem (do C# 7 ao C# 12), o C# absorveu os melhores recursos de casamento de padrões de linguagens funcionais como F# e Haskell, transformando o switch de uma instrução (statement) em uma expressão funcional (expression):

// Sintaxe Clássica Imperativa (Verbosa e Sujeita a Esquecimento de 'break')
switch (status)
{
    case 1:
        resultado = "Ativo";
        break;
    default:
        resultado = "Inativo";
        break;
}

// Sintaxe Moderna Declarativa com Switch Expression (C# 8+)
string resultado = status switch
{
    1 => "Ativo",
    _ => "Inativo" // Padrão de descarte (discard) substitui default
};

⚙️ 2. Tipologia de Padrões Modernos

2.1 Padrões Relacionais e Lógicos (and, or, not)

Permitem testar faixas numéricas de forma legível sem repetir o identificador da variável:

string statusPressao = pressaoBar switch
{
    < 1.0 => "Subpressão Perigosa",
    >= 1.0 and <= 10.0 => "Pressão Nominal",
    > 10.0 and <= 25.0 => "Alerta de Sobrecarga",
    _ => "Falha Crítica de Válvula"
};

2.2 Padrões de Propriedade (Property Patterns)

Inspecionam o estado interno de objetos aninhados sem necessidade de encadeamentos defensivos com if:

bool aptoParaOperacao = dispositivo switch
{
    { Calibrado: true, Temperatura: < 70.0, Conexao: { Status: "ONLINE" } } => true,
    _ => false
};

2.3 Padrões de Lista (List Patterns - C# 11/12)

Permitem casar fatias inteiras de arrays e spans usando o operador de fatia (slice pattern ..):

int[] cabecalhoPacote = [0xFF, 0x01, 0x02, 0xEE];

string tipo = cabecalhoPacote switch
{
    [0xFF, .., 0xEE] => "Pacote Válido com Marcadores de Início e Fim",
    [0x00, ..]       => "Pacote Nulo de Inicialização",
    _                => "Formato Inválido"
};

📦 3. Exaustividade e Análise Estática de Casos Não Cobertos

Uma das maiores vantagens das Switch Expressions sobre os antigos blocos imperativos é que o compilador Roslyn impõe a verificação de exaustividade (Exhaustiveness Checking).

Se você criar uma expressão switch sobre uma enumeração ou união de tipos e esquecer de tratar uma das opções possíveis sem fornecer o padrão de descarte _, o compilador emitirá um aviso estrito: CS8509: The switch expression does not handle all possible values of its input type. Em tempo de execução, caso um valor inesperado alcance uma expressão não exaustiva, a CLR dispara imediatamente uma SwitchExpressionException, prevenindo que a aplicação prossiga em um estado corrompido.


📊 4. Matriz Comparativa: if/else vs switch clássico vs switch expression

Critério if / else if Tradicional switch Statement (C# 1-6) switch Expression (C# 8+)
Natureza Instrução de controle Instrução de controle Expressão de retorno direto
Exaustividade Não verificada Não verificada Verificada pelo compilador
Combinação Lógica Operadores &&, \|\|, ! Rígida por caso fixo Padrões and, or, not
Desestruturação Manual Não suportada Suporte total a Tuplas, Properties e Listas

🔬 5. Laboratório de Arquitetura: Jump Tables e Emissão IL do Roslyn

Quando você compila uma expressão switch com valores densos e conhecidos, o RyuJIT não gera uma cadeia lenta de comparações sequenciais (cmp e jne). Em vez disso, ele emite a instrução IL switch, que o compilador de máquina traduz diretamente em uma Jump Table indexada em hardware:

  • O endereço de destino do código é calculado em tempo constante $O(1)$ através de um salto indireto indexado (jmp [tabela + reg*8]).
  • O branch predictor do processador sofre zero penalidade de predição errônea, permitindo que despachadores de mensagens processem centenas de milhões de eventos por segundo em aplicações financeiras e de rede.