C# – Types énumérés

Ce qui suit se veut un bref survol des énumérations en C#. Une énumération, vue de manière superficielle, est un type dont les valeurs acceptables font partie d'une série finie de valeurs symboliques auxquelles des valeurs entières sont associées, ce qui peut remplacer une écriture plus fastidieuse :

Avec constantes Avec énumérations
const int DIMANCHE = 0;
const int LUNDI    = DIMANCHE + 1;
const int MARDI    = DIMANCHE + 2;
const int MERCREDI = DIMANCHE + 3;
const int JEUDI    = DIMANCHE + 4;
const int VENDREDI = DIMANCHE + 5;
const int SAMEDI   = DIMANCHE + 6;
enum Jour
{
   Dimanche,
   Lundi,
   Mardi,
   Mercredi,
   Jeudi,
   Vendredi,
   Samedi
}

Par défaut, le premier symbole d'une énumération correspond à la valeur entière zéro, et les symboles subséquents ont les valeurs successives (1, 2, 3, ...), mais il est possible de contrôler plus finement cette attribution de valeurs si désiré :

enum Fruits
{
   Tomate = -1, // oui, c'est un fruit
   Orange, // vaut 0
   Pomme, // vaut 1
   Citron = 10,
   Cerise, // vaut 11
   Lime = 10 // vaut aussi 10... Légal, mais pas nécessairement une bonne idée
}

 

La classe Test ci-dessous définit un type énuméré Jour pouvant représenter un ensemble de valeurs symboliques correspondant aux jours de la semaine. Il est possible d'utiliser des variables et des paramètres de type Jour, tout comme il est possible de comparer des instances de Jour entre elles.

Le passage d'un entier à un Jour et la transformation d'un Jour en texte sont présentés dans la méthode Main().

using System;
using System.Collections;
namespace Z
{
  class Test
  {
     enum Jour { Dimanche, Lundi, Mardi, Mercredi, Jeudi, Vendredi, Samedi }
     const int NB_JOURS = 7;
     static bool EstFérié(Jour j) =>
        j == Jour.Samedi || j == Jour.Dimanche;
     static void Main(string[] args)
     {
        Jour j = (Jour) new Random().Next(NB_JOURS);
        string nom = Enum.GetName(typeof(Jour), j);
        if (EstFérié(j))
           Console.WriteLine($"{nom} est férié");
        else
           Console.WriteLine($"{nom} n'est pas férié");
     }
  }
}

Notez qu'il est possible de convertir une valeur hors bornes en une énumération, ce qui peut surprendre celles et ceux qui ne s'y attendent pas. Ainsi, ceci :

using System;
public class Program
{
   enum Jour { Dimanche, Lundi, Mardi, Mercredi, Jeudi, Vendredi, Samedi }
   public static void Main()
   {
      for(int i = 0; i != 10; ++i)
         Console.WriteLine($"{{(Jour)i}} vaut {i}");
   }
}

Énumération et choix de substrat

Comme c'est le cas avec plusieurs autres langages, les enum de C# utilisent des types entiers à titre de substrat, et le substrat par défaut est int. Il est cependant possible d'écrire des enum qui reposent sur des types entiers autres que int. Par exemple :

enum Jour : byte { Dimanche, Lundi, Mardi, Mercredi, Jeudi, Vendredi, Samedi }

Ceci peut permettre de contrôler la taille des valeurs énumérées en mémoire et la plage de valeurs possibles. En particulier, pour les gens qui utilisent des enum pour représenter des masques dans le but de réaliser des opérations bit à bit, ce contrôle du subtrat permet d'obtenir des masques de plus de 32 bits.

Cas particulier : énumération et char

Il arrive que l'on souhaite utiliser enum avec des char, pour ne pas avoir à écrire une série de constantes comme :

const char MUR = '#';
const char VIDE = ' ';
// etc.

C'est évidemment (!) possible, parce que char est (techniquement, car il y a un piège ici; voir plus bas) un type entier et que les enum utilisent des types entiers à titre de substrat. Ainsi, ceci fonctionne très bien :

enum Guidis {  Mur = '#', Vide = ' ' } // etc.
static void Main(string[] args)
{
   Guidis guidi = Guidis.Mur;
   Console.WriteLine(guidi);
   Console.WriteLine((char)guidi);
   Console.WriteLine((int)guidi);
   Console.WriteLine((Guidis)'#');
   guidi = Guidis.Vide;
   Console.WriteLine((int)guidi);
   // si vous voulez parcourir diverses valeurs, vous pouvez envisager un tableau
   Guidis[] options = new[] { Guidis.Mur, Guidis.Vide };
}

Notez toutefois que C# n'est pas tout à fait cohérent sur ce point. En effet, s'il est possible d'écrire des enum qui reposent sur des types entiers autres que int, il n'est pas possible d'utiliser un char comme substrat (même si on peut mettre des char dans les entiers qui composent un enum, comme démontré ici, comme on peut d'ailleurs mettre un char dans un int).

Liens complémentaires

Quelques liens pour enrichir le propos.


Valid XHTML 1.0 Transitional

CSS Valide !