1. Introdução
Você já sabe escrever esse tipo de código:
switch (color)
{
case "red":
Console.WriteLine("Pare!");
break;
case "yellow":
Console.WriteLine("Espere...");
break;
case "green":
Console.WriteLine("Pode ir!");
break;
default:
Console.WriteLine("Que cor é essa?");
break;
}
Mas e se a gente quiser atribuir um valor diferente pra uma variável dependendo do parâmetro de entrada, tipo retornar uma string baseada em um número de uma função? Antes dos switch-expressions a gente tinha que fazer umas gambiarras assim:
string meaning;
switch (number)
{
case 42:
meaning = "Resposta para a pergunta fundamental da vida, do universo e tudo mais";
break;
case 7:
meaning = "Número da sorte";
break;
default:
meaning = "Número comum";
break;
}
Não parece muito elegante pra uma linguagem do século XXI, né? Dá vontade de já retornar o valor direto, igual rola nas linguagens funcionais.
É aí que entram os switch-expressions — uma das features mais legais (e recentes) do C#, a partir da versão 8.0.
2. switch-expressions: sintaxe que dá vontade de abraçar
Comparando: statement e expression
O switch clássico é um statement ("comando"), já o switch-expression é uma expression, ou seja, ele calcula um valor e você pode já atribuir pra uma variável ou retornar de um método.
Estrutura do switch-expression:
var result = value switch
{
pattern1 => expression1,
pattern2 => expression2,
_ => defaultExpression // "underline" - é o "senão"
};
Por exemplo:
int number = 42;
string meaning = number switch
{
42 => "Resposta para a pergunta fundamental da vida, do universo e tudo mais",
7 => "Número da sorte",
_ => "Número comum"
};
Console.WriteLine(meaning); // => Resposta para a pergunta fundamental da vida, do universo e tudo mais
Fica tudo direto, legível, sem aquele monte de código, nem um break; perdido.
Repara só: o underline _ — é pra "pegar todos os outros casos", igual o default.
3. switch-expressions e patterns: como eles se combinam
É aqui que a diversão começa de verdade. Nos switch-expressions você pode usar não só valores normais, mas também patterns: checar intervalos, tipo, propriedades de objetos, deconstrução (quebrar o objeto em partes), e até combinatorial patterns (and, or, not).
Exemplos de patterns em switch-expression
Patterns constantes
Isso é o que a gente já fez ali em cima: comparar com 42, 7 e por aí vai.
Intervalos e comparações
int age = 17;
string category = age switch
{
< 18 => "Menor de idade",
>= 18 and <= 65 => "Adulto",
> 65 => "Pessoa idosa",
_ => "Categoria de idade desconhecida"
};
Console.WriteLine(category);
Aliás, repara — dá pra usar várias condições juntas! O C# tá cada vez mais expressivo.
Patterns de tipo (Type Patterns)
Imagina que você tem um objeto que pode ser de vários tipos (tipo object value;). Dá pra tratar cada tipo assim:
object value = 3.14;
string description = value switch
{
int i => $"Número inteiro: {i}",
double d => $"Número decimal: {d:F2}",
string s => $"Isso é uma string: '{s}'",
null => "null!",
_ => "Outra coisa"
};
Console.WriteLine(description); // => Número decimal: 3.14
Patterns relacionados (Property Patterns e Positional Patterns)
No C# 8 e depois, dá pra checar valores de propriedades direto no switch-expression.
Exemplo com objeto
public class User
{
public string Name { get; set; }
public int Age { get; set; }
}
User user = new User { Name = "Anna", Age = 17 };
string welcome = user switch
{
{ Age: < 18 } => $"Oi, {user.Name}! Você é adolescente.",
{ Age: >= 18 and <= 65 } => $"E aí, {user.Name}! Vida adulta é massa.",
{ Age: > 65 } => $"Bem-vindo, {user.Name}! Você é sempre bem-vindo.",
_ => "Idade desconhecida"
};
Console.WriteLine(welcome);
Aqui nas chaves { Age: < 18 } — é um property pattern, ou seja, a gente checa só a propriedade, não o objeto inteiro.
4. Novos patterns do C# 11-14
O C# tá cada vez mais direto e flexível. Recentemente chegaram os combinatorial patterns: and, or, not, e também melhoraram os positional patterns. Bora ver como funciona.
Patterns lógicos: and, or, not
Dá pra montar condições complexas, igual lógica matemática!
int temperature = 25;
string result = temperature switch
{
< 0 => "Congelando!",
>= 0 and < 20 => "Fresquinho",
>= 20 and < 30 => "Confortável",
>= 30 or <= -30 => "Extremo!",
_ => "Temperatura estranha"
};
Se quiser excluir casos, tranquilo:
int score = 80;
string grade = score switch
{
>= 90 => "Excelente",
>= 60 and not >= 90 => "Bom",
_ => "Ruim"
};
Deconstrução (Positional Patterns)
Se você tem uma struct ou record que suporta deconstrução, o C# deixa quebrar o objeto direto no switch-expression:
public record Point(int X, int Y);
Point p = new Point(10, 20);
string desc = p switch
{
(0, 0) => "Origem",
(var x, 0) => $"No eixo X, X={x}",
(0, var y) => $"No eixo Y, Y={y}",
(var x, var y) when x == y => $"Na diagonal: {x}",
_ => $"No ponto ({p.X}, {p.Y})"
};
Console.WriteLine(desc); // => No ponto (10, 20)
5. Quando e por que usar switch-expressions
No C# moderno, switch-expressions não são só uma "modinha", mas um jeito real de evitar código repetitivo, deixar o código mais compacto, fácil de testar e de manter. Isso é super importante quando você tá escrevendo parsers, handlers de comandos, lógica de negócio, configuração de regras — em qualquer lugar que precisa ramificar a execução por critérios complexos, não só por valores, mas também por tipos, intervalos, propriedades, combinações.
Em entrevistas
- Como você trataria diferentes respostas do usuário?
- Como fazer pra retornar valores diferentes de uma função, dependendo do tipo e do valor?
- Como você adicionaria novas regras sem um monte de if-else?
Mostra um switch-expression com patterns! Isso já mostra que você manja das novidades da linguagem e tem um estilo de código daora.
Tabela: comparação entre switch-statement e switch-expression
| Característica | switch statement | switch expression |
|---|---|---|
| Tipo | statement (comando) | expression (expressão) |
| Precisa de break | sim | não precisa |
| Pode retornar valor | só via variável | sim, já retorna valor |
| Pode usar patterns | parcialmente | totalmente (type, property, etc.) |
| Pegadinha | dá pra esquecer o break | todos os caminhos precisam retornar valor |
6. Erros comuns e pegadinhas
- Quem tá começando sempre confunde switch-statement ("comando") e switch-expression ("expressão"). Por exemplo, esquece que no switch-expression não precisa de break;, e que todos os ramos têm que retornar valor.
- Se esquecer o ramo _, o compilador avisa: "e se não bater em nada?".
- No switch-expression não dá pra usar goto (ainda bem!).
- Se repetir condição (tipo, dois patterns iguais), o compilador também não deixa passar.
- Fica ligado no tipo do valor retornado do switch-expression: ele tem que ser compatível com o tipo da variável onde você tá jogando o resultado.
GO TO FULL VERSION