C# – sélectives « switch » sous forme d'énoncé ou d'expression

Quelques raccourcis :

Le langage C# supporte deux formes grammaticales de sélectives (switch). La forme classique, qui est un énoncé (un peu comme un if ou un for), et donc n'a pas de valeur propre lorsqu'elle est évaluée, et la forme « expression » qui, lorsqu'elle est évaluée prend une valeur parmi plusieurs.

Les deux formes ont leur raison d'être. Ce court texte présente les deux et vise à montrer comment les utiliser.

Forme « énoncé »

La forme la plus connue de la sélective est sans doute l'énoncé, qui existe sous une forme ou l'autre dans la plupart des langages de programmation. Elle permet de remplacer un enchaînement d'alternatives if ... else if ... else if ... else ... sur une même expression par quelque chose de plus simple :

Enchaînement d'alternatives Forme sélective
// ...
const char DROITE = 'd',
           HAUT = 'w',
           GAUCHE = 'a',
           BAS = 's';
// ...
class Personnage { /* ... */ }
// ...
static class MoteurDéplacement
{
   static void DéplacerDroite(Personnage p) { /* ... */ }
   static void DéplacerHaut(Personnage p) { /* ... */ }
   static void DéplacerGauche(Personnage p) { /* ... */ }
   static void DéplacerBas(Personnage p) { /* ... */ }
   static void MouvementInvalide(char clé) { /* ... */ }
   public static void Déplacer(Personnage p, char clé)
   {
      if(clé == DROITE)
      {
         DéplacerDroite(p);
      }
      else if(clé == HAUT)
      {
         DéplacerHaut(p);
      }
      else if(clé == GAUCHE)
      {
         DéplacerGauche(p);
      }
      else if(clé == BAS)
      {
         DéplacerBas(p);
      }
      else
      {
         MouvementInvalide(clé);
      }
   }
}
// ...
// ...
const char DROITE = 'd',
           HAUT = 'w',
           GAUCHE = 'a',
           BAS = 's';
// ...
class Personnage { /* ... */ }
// ...
static class MoteurDéplacement
{
   static void DéplacerDroite(Personnage p) { /* ... */ }
   static void DéplacerHaut(Personnage p) { /* ... */ }
   static void DéplacerGauche(Personnage p) { /* ... */ }
   static void DéplacerBas(Personnage p) { /* ... */ }
   static void MouvementInvalide(char clé) { /* ... */ }
   public static void Déplacer(Personnage p, char clé)
   {
      switch(clé)
      {
      case DROITE:
         DéplacerDroite(p);
         break;
      case HAUT:
         DéplacerHaut(p);
         break;
      case GAUCHE:
         DéplacerGauche(p);
         break;
      case BAS:
         DéplacerBas(p);
         break;
      default:
         MouvementInvalide(clé);
         break;
      }
   }
}
// ...

Dans cet exemple, nous examinons la valeur de la variable clé mais si nous remplacions cette variable par un calcul (p. ex. : appel d'une fonction LireTouche) il faudrait, à gauche, s'assurer de n'appeler la fonction qu'une seule fois puis d'utiliser le résultat du calcul (nous ne voudrions pas lire plusieurs fois une touche, n'est-ce pas?), alors qu'à droite nous pourrions évaluer la valeur de l'expression dans le switch lui-même puis comparer (case...) le résultat de cette évaluation avec plusieurs constantes.

Forme « expression »

Parfois, nous utilisons une sélective pour choisir une valeur parmi plusieurs. Dans ce cas, la forme « expression » devient intéressante. Pour bien comprendre, comparez les fonctions ci-dessous qui font exactement la même chose, mais à l'aide d'un énoncé à gauche (un seul return), encore un énoncé au centre (plusieurs return) et à l'aide d'une expression à droite (un seul return) :

Forme « énoncé » (un seul return) Forme « énoncé » (plusieurs return) Forme « expression » (un seul return)
// ...
public static string NommerNombre(int n)
{
   string nom;
   switch(n)
   {
   case 0:
      nom = "zéro";
      break;
   case 1:
      nom = "un";
      break;
   case 2:
      nom = "deux";
      break;
   default:
      nom = "mystère";
      break;
   }
   return nom;
}
// ...
// ...
public static string NommerNombre(int n)
{
   switch(n)
   {
   case 0: return "zéro";
   case 1: return "un";
   case 2: return "deux";
   default: return "mystère";
   }
}
// ...
// ...
public static string NommerNombre(int n) =>
   n switch
   {
      0 => "zéro",
      1 => "un",
      2 => "deux",
      _ => "mystère"
   }
// ...

La forme de gauche reposant sur un énoncé, elle s'exprime de manière procédurale : on déclare une variable, on décide par voie de sélective la valeur à lui attribuer, puis on retourne cette valeur. La forme au centre tient compte du fait que chaque cas se limite au fond à retourner une valeur, et utilise un return par cas à couvrir (attention de ne pas en oublier, cela dit!); certains accepteront cette forme, d'autres ne l'apprécieront pas.

La forme de droite est une expression. La fonction se limite à un return, mais ce return prend une valeur qui dépend de celle du paramètre n. Le cas _ représente le « default » d'un switch sous forme « énoncé » (ici, nous avons une valeur par défaut, mais on verra souvent une levée d'exception dans un tel cas).

Lectures complémentaires

Quelques liens pour enrichir le propos.


Valid XHTML 1.0 Transitional

CSS Valide !