Capítulo 03: Estruturas Condicionais, Switch Expressions e Pattern Matching
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.