Menu

Instruction switch en C# : case, break, default et cas multiples

Comment fonctionne l'instruction switch en C# : switch sur des valeurs int, string, char et enum, pourquoi chaque case a besoin de break (erreur CS0163), empiler des étiquettes case pour plusieurs valeurs, goto case, default, la casse des chaînes, et les étiquettes à pattern avec when.

Cette page contient des éditeurs exécutables - modifiez, exécutez et voyez la sortie instantanément.

Une instruction switch compare une valeur à une liste d'étiquettes case constantes et exécute la section qui correspond. En C#, chaque section doit se terminer par break (ou une autre instruction qui la quitte), si bien qu'un cas ne peut jamais glisser silencieusement dans le suivant.

Sortie :

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

La valeur entre parenthèses est évaluée une fois et comparée à chaque étiquette. default s'exécute quand rien ne correspond ; il est facultatif et peut apparaître n'importe où dans la liste, même s'il se place en général à la fin. S'il n'y a ni correspondance ni default, le switch entier ne fait rien.

Chaque section a besoin d'un break

En C, C++, Java et JavaScript, oublier break fait glisser l'exécution dans le cas suivant. C# transforme cette erreur en erreur de compilation :

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;
}

La règle est que la fin de la liste d'instructions d'une section ne doit pas être atteignable. break est la façon habituelle de la respecter, mais tout ce qui quitte la section fonctionne :

  • return quitte toute la méthode, ce qui est souvent la forme la plus propre dans une petite fonction.
  • throw lève une exception pour une valeur qui ne devrait jamais se produire.
  • continue passe à l'itération suivante quand le switch se trouve dans une boucle.
  • goto case et goto default sautent délibérément vers une autre section.

La dernière section n'est pas exemptée. Un default: en bas sans break échoue avec CS8070, Control cannot fall out of switch from final case label ('default:').

Plusieurs valeurs dans un même case

Les étiquettes sans instruction entre elles partagent la section située en dessous. C'est le seul enchaînement que C# autorise, car une étiquette vide ne peut cacher aucun code :

Sortie :

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

Chaque section se termine ici par return, donc aucun break n'est nécessaire (un break après un return serait du code inaccessible). Deux étiquettes de même valeur sont une erreur, CS0152 The switch statement contains multiple cases with the label value '1', et chaque étiquette doit être une constante de compilation : une variable dans un case échoue avec « a constant value is expected ».

switch sur une string

Les chaînes sont la valeur de switch la plus courante après les entiers. La comparaison est ordinale et sensible à la casse, donc normalisez l'entrée avant le switch :

Sortie :

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

Sans ToLowerInvariant, "STOP" atteindrait default. Faire un switch sur une valeur null est légal : elle ne correspond à aucune constante chaîne et tombe dans default, donc le switch lui-même ne lève jamais d'exception.

switch sur un enum

Les enums sont ce pour quoi switch a été conçu : un ensemble fermé de valeurs nommées.

Sortie :

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

Le compilateur ne vérifie pas qu'une instruction switch couvre chaque membre de l'enum, et une variable enum peut contenir n'importe quel entier de son type sous-jacent ((OrderStatus)42 est légal). Le default qui lève une exception transforme un cas oublié en échec immédiat et évident, au lieu d'une absence d'action silencieuse.

goto case et goto default

Quand un cas doit vraiment se poursuivre dans un autre, C# vous oblige à écrire le saut :

Sortie :

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

goto case prend une constante qui doit correspondre à l'une des étiquettes du même switch. C'est rare dans du vrai code : un comportement partagé est en général plus clair sous forme d'une méthode que plusieurs cas appellent. C'est tout de même la réponse à « comment enchaîner les cas en C# ».

Les variables dans les cases

Tout le bloc switch forme une seule portée, donc deux cas ne peuvent pas déclarer une variable du même nom :

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;
}

Entourez le corps de chaque section d'accolades pour lui donner sa propre portée : case "square": { int area = side * side; ... break; }.

break dans une boucle

break dans un case quitte le switch, pas la boucle qui l'entoure. continue fait l'inverse : un switch n'est pas une boucle, donc continue passe à l'itération suivante de la boucle.

Sortie :

end marker found
Total: 134

La boucle a continué après "end" et a ajouté 99. Pour arrêter la boucle depuis un switch, positionnez un indicateur et testez-le après le switch, ou déplacez la boucle dans une méthode et utilisez return. La page sur break et continue compare les options.

Étiquettes à pattern et when

Depuis C# 7.0, une étiquette case peut être un pattern au lieu d'une constante : elle peut tester le type de la valeur et ajouter une condition when. Cette forme est courante dans le code C# moderne :

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}";
    }
}

Avec les patterns, l'ordre compte : le premier cas qui correspond l'emporte, et le compilateur signale une erreur quand un cas ne peut jamais être atteint parce qu'un cas précédent le couvre déjà (placer case int n: au-dessus de case int n when n < 0: échoue). La clause when fonctionne aussi sur les cas constants : case 0 when isAdmin:. C# 9 a ajouté les patterns relationnels et logiques, si bien qu'un cas peut s'écrire case >= 90: ou case 'a' or 'e' or 'i':.

En C# 7 sans patterns, le même aiguillage par type est une chaîne de if avec le pattern de type is :

Sortie :

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

Quand chaque branche d'un switch ne fait que calculer une valeur, l'expression switch est encore plus courte : var grade = score switch { >= 90 => "A", >= 80 => "B", _ => "C" };. La page sur l'expression switch couvre sa syntaxe, ses patterns et ses règles d'exhaustivité.

Sur quoi peut-on faire un switch

Type de valeurCas constantsRemarques
int, long, byte et autres entiersouile cas classique
charouicase 'a':
stringouiordinal, sensible à la casse, null va dans default
boolouilégal, mais un if est plus clair
tout enumouiaucune vérification d'exhaustivité
double, decimaldepuis C# 7constantes uniquement ; les intervalles demandent les patterns relationnels de C# 9
tout autre typedepuis C# 7via les patterns de type, case Circle c:

Questions fréquentes

break est-il obligatoire dans un switch C# ?

Chaque section case doit se terminer par une instruction qui la quitte : en général break, mais return, throw, continue (dans une boucle) ou goto case comptent aussi. Glisser de la fin d'une section dans la suivante est une erreur de compilation, CS0163 Control cannot fall through from one case label ('case 1:') to another, et cela vaut aussi pour la dernière section.

Comment gérer plusieurs valeurs dans un même case en C# ?

Empilez les étiquettes sans rien entre elles : case "sat": case "sun": Console.WriteLine("weekend"); break;. Les étiquettes case vides peuvent passer à l'étiquette suivante ; seule une section qui contient des instructions doit se terminer par break. Depuis C# 9, un case à pattern peut aussi s'écrire case 1 or 2 or 3:.

Un switch sur une string est-il sensible à la casse en C# ?

Oui. Les cas de chaîne sont comparés par égalité ordinale sensible à la casse, donc "Yes" ne correspond pas à case "yes":. Normalisez d'abord la valeur avec switch (input.Trim().ToLowerInvariant()). Une chaîne null ne correspond à aucun cas constant et va dans default.

Un switch C# peut-il enchaîner les cas comme en C ou en Java ?

Pas implicitement. Quand vous voulez qu'un cas se poursuive dans un autre, dites-le avec goto case <value>; ou goto default;. Chaque enchaînement devient ainsi visible dans le code, c'est pourquoi C# interdit la version silencieuse.

Quelle est la différence entre une instruction switch et une expression switch en C# ?

Une instruction switch exécute des instructions et a besoin de case, break et default. Une expression switch (C# 8 et plus) produit une valeur : var label = n switch { 0 => "zero", > 0 => "positive", _ => "negative" };. Utilisez l'expression quand chaque branche ne fait que calculer un résultat.

Coddy programming languages illustration

Apprendre à coder avec Coddy

COMMENCER