Menu

switch case em C#: case, break, default e vários casos

Como a instrução switch funciona em C#: switch com valores int, string, char e enum, por que todo case precisa de break (erro CS0163), empilhar rótulos case para vários valores, goto case, default, diferença entre maiúsculas e minúsculas em strings e rótulos case com padrões e when.

Esta página tem editores executáveis - edite, execute e veja a saída na hora.

Uma instrução switch compara um valor com uma lista de rótulos case constantes e executa a seção correspondente. Em C#, toda seção precisa terminar com break (ou outra instrução que saia dela), então um case nunca continua no próximo sem aviso.

Saída:

200: OK
302: redirect
404: not found
500: unhandled status

O valor entre parênteses é avaliado uma vez e comparado com cada rótulo. default executa quando nada corresponde; ele é opcional e pode aparecer em qualquer lugar da lista, embora normalmente venha por último. Se não houver correspondência nem default, o switch inteiro não faz nada.

Toda seção precisa de break

Em C, C++, Java e JavaScript, esquecer o break faz a execução escorregar para o próximo case. C# transforma esse erro em erro de compilação:

switch (level)
{
    case 1:
        Console.WriteLine("read");
        // error CS0163: Control cannot fall through from one case label ('case 1:') to another
    case 2:
        Console.WriteLine("write");
        break;
}

A regra é que o fim da lista de instruções de uma seção não pode ser alcançável. break é a forma usual de cumprir isso, mas qualquer coisa que saia da seção funciona:

  • return sai do método inteiro, o que muitas vezes é a forma mais limpa dentro de um método auxiliar pequeno.
  • throw lança uma exceção para um valor que nunca deveria aparecer.
  • continue pula para a próxima iteração quando o switch está dentro de um laço.
  • goto case e goto default pulam para outra seção de propósito.

A última seção não é exceção. Um default: no final sem break falha com CS8070, Control cannot fall out of switch from final case label ('default:').

Vários valores em um case

Rótulos sem instruções entre eles compartilham a seção abaixo. Esse é o único tipo de fall through que C# permite, porque um rótulo vazio não pode esconder código:

Saída:

'O' is a vowel
'k' is a consonant or symbol
' ' is a space
'7' is a digit

Cada seção aqui termina com return, então nenhum break é necessário (um break depois de um return seria código inalcançável). Dois rótulos com o mesmo valor são um erro, CS0152 The switch statement contains multiple cases with the label value '1', e todo rótulo precisa ser uma constante de tempo de compilação: uma variável em um case falha com "a constant value is expected".

switch com string

Strings são o valor de switch mais comum depois dos inteiros. A comparação é ordinal e diferencia maiúsculas de minúsculas, então normalize a entrada antes do switch:

Saída:

Starting the server
Stopping the server
Server is running
Unknown command: restart
Unknown command: (none)

Sem ToLowerInvariant, "STOP" chegaria ao default. Um valor null é permitido no switch: ele não corresponde a nenhuma constante string e cai no default, então o switch em si nunca lança exceção.

switch com enum

Enums são exatamente o caso para o qual o switch foi feito: um conjunto fechado de valores com nome.

Saída:

Pending: wait for payment
Paid: pack and ship
Shipped: track the parcel
Delivered: nothing, order is closed
Cancelled: nothing, order is closed
ArgumentOutOfRangeException for value 42

O compilador não verifica se uma instrução switch cobre todos os membros do enum, e uma variável enum pode guardar qualquer inteiro do tipo subjacente ((OrderStatus)42 é válido). O default que lança uma exceção transforma um case esquecido em uma falha imediata e óbvia, em vez de algo que silenciosamente não faz nada.

goto case e goto default

Quando um case realmente deve continuar em outro, C# obriga você a escrever o salto:

Saída:

admin:
  manage users
  edit posts
  read posts
editor:
  edit posts
  read posts
guest:
  read posts

goto case recebe uma constante que precisa corresponder a um dos rótulos do mesmo switch. É raro em código real: comportamento compartilhado costuma ficar mais claro como um método chamado por vários cases. Ainda assim, é a resposta para "como fazer fall through em C#".

Variáveis dentro dos cases

O bloco switch inteiro é um único escopo, então dois cases não podem declarar uma variável com o mesmo nome:

switch (shape)
{
    case "square":
        int area = side * side;
        break;
    case "rectangle":
        int area = width * height;   // error CS0128: A local variable or function named 'area' is already defined in this scope
        break;
}

Envolva o corpo de cada seção em chaves para dar a ela um escopo próprio: case "square": { int area = side * side; ... break; }.

break dentro de um laço

break em um case sai do switch, não do laço em volta. continue faz o contrário: um switch não é um laço, então continue vai para a próxima iteração do laço.

Saída:

end marker found
Total: 134

O laço continuou depois de "end" e somou 99. Para parar o laço de dentro de um switch, defina uma flag e teste-a depois do switch, ou mova o laço para um método e use return. A página de break e continue compara as opções.

Rótulos case com padrões e when

Desde o C# 7.0, um rótulo case pode ser um padrão em vez de uma constante: ele pode testar o tipo do valor e adicionar uma condição when. Essa forma é comum em código C# moderno:

static string Describe(object value)
{
    switch (value)
    {
        case null:
            return "nothing";
        case int n when n < 0:
            return $"negative int {n}";
        case int n:
            return $"int {n}";
        case string s when s.Length == 0:
            return "empty string";
        case string s:
            return $"string \"{s}\"";
        default:
            return $"other: {value.GetType().Name}";
    }
}

Com padrões, a ordem importa: o primeiro case que corresponde vence, e o compilador reporta um erro quando um case nunca pode ser alcançado porque um anterior já o cobre (colocar case int n: acima de case int n when n < 0: falha). A cláusula when também funciona em cases constantes: case 0 when isAdmin:. O C# 9 adicionou padrões relacionais e lógicos, então um case pode ser case >= 90: ou case 'a' or 'e' or 'i':.

No C# 7 sem padrões, o mesmo despacho por tipo é uma cadeia de if com o padrão de tipo is:

Saída:

negative int -3
int 12
empty string
string "hi"
other: Decimal
nothing

Quando cada ramo de um switch só calcula um valor, a expressão switch é ainda mais curta: var grade = score switch { >= 90 => "A", >= 80 => "B", _ => "C" };. A página da expressão switch cobre a sintaxe, os padrões e as regras de exaustividade.

Com o que dá para fazer switch

Tipo do valorCases constantesObservações
int, long, byte e outros inteirossimo caso clássico
charsimcase 'a':
stringsimordinal, diferencia maiúsculas de minúsculas, null vai para default
boolsimválido, mas um if é mais claro
qualquer enumsimsem verificação de exaustividade
double, decimala partir do C# 7só constantes; intervalos precisam dos padrões relacionais do C# 9
qualquer outro tipoa partir do C# 7por meio de padrões de tipo, case Circle c:

Perguntas frequentes

O break é obrigatório em um switch em C#?

Toda seção case precisa terminar em uma instrução que saia dela: normalmente break, mas return, throw, continue (dentro de um laço) ou goto case também servem. Passar do fim de uma seção para a próxima é um erro de compilação, CS0163 Control cannot fall through from one case label ('case 1:') to another, e isso inclui a última seção.

Como tratar vários valores em um mesmo case de um switch em C#?

Empilhe os rótulos sem nada entre eles: case "sat": case "sun": Console.WriteLine("weekend"); break;. Rótulos case vazios podem passar para o próximo rótulo; só uma seção que contém instruções precisa terminar em break. A partir do C# 9, um case com padrão também pode escrever case 1 or 2 or 3:.

Um switch com string em C# diferencia maiúsculas de minúsculas?

Sim. Os cases de string são comparados por igualdade ordinal, que diferencia maiúsculas de minúsculas, então "Yes" não corresponde a case "yes":. Normalize o valor antes com switch (input.Trim().ToLowerInvariant()). Uma string null não corresponde a nenhum case constante e vai para default.

Um switch em C# pode fazer fall through como em C ou Java?

Não de forma implícita. Quando você quer que um case continue em outro, diga isso com goto case <value>; ou goto default;. Assim todo fall through fica visível no código, e é por isso que C# proíbe a versão silenciosa.

Qual a diferença entre a instrução switch e a expressão switch em C#?

Uma instrução switch executa instruções e precisa de case, break e default. Uma expressão switch (C# 8 em diante) produz um valor: var label = n switch { 0 => "zero", > 0 => "positive", _ => "negative" };. Use a expressão quando cada ramo só calcula um resultado.

Coddy programming languages illustration

Aprenda a programar com o Coddy

COMEÇAR