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 :
returnquitte toute la méthode, ce qui est souvent la forme la plus propre dans une petite fonction.throwlève une exception pour une valeur qui ne devrait jamais se produire.continuepasse à l'itération suivante quand leswitchse trouve dans une boucle.goto caseetgoto defaultsautent 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 valeur | Cas constants | Remarques |
|---|---|---|
int, long, byte et autres entiers | oui | le cas classique |
char | oui | case 'a': |
string | oui | ordinal, sensible à la casse, null va dans default |
bool | oui | légal, mais un if est plus clair |
tout enum | oui | aucune vérification d'exhaustivité |
double, decimal | depuis C# 7 | constantes uniquement ; les intervalles demandent les patterns relationnels de C# 9 |
| tout autre type | depuis C# 7 | via 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.