Enums

Déclaration

Ensemble de constantes nommées dont la valeur est de type entier : → Contrairement au C♯, il faut définir la valeur de tous les membres de l'enum :

type ColorN =
    | Red   = 1
    | Green = 2
    | Blue  = 3

☝️ Noter la différence de syntaxe avec un type union "enum-like" (Style "enum") :

type Color = Red | Green | Blue

Type sous-jacent

  • Contrairement au C♯, il n'y a pas de type sous-jacent par défaut en F♯.

  • Le type sous-jacent est défini au moyen des littéraux définissant les valeurs des membres :

    • 1, 2, 3int

    • 1uy, 2uy, 3uybyte

    • Etc. - cf. Literals

Corolaire : il faut utiliser le même type pour tous les membres, sinon cela ne compile pas !

type ColorN =
    | Red   = 1
    | Green = 2
    | Blue  = 3uy
// 💥 ~~~~~~~~~~~
// Cette expression était censée avoir le type `int` 
// mais elle a ici le type `byte`

Char

Le type char peut être utilisé comme type sous-jacent :

Casse

Autre différence avec les types union, les membres peuvent être en camelCase :

Usage

⚠️ Contrairement aux unions, l'emploi d'un membre (a.k.a littéral) d'enum est forcément qualifié

Cast via helpers int et enum (mais pas char) :

Pattern matching

⚠️ Contrairement aux unions, le pattern matching n'est pas exhaustif

Valeurs

On peut utiliser la méthode System.Enum.GetValues() pour obtenir la liste des membres d'une enum. Par contre, le type de retour est faiblement typé : Array (tableau non générique). → Il suffit d'encapsuler cette méthode dans une fonction helper telle que :

💡 Voir également Extras

Flags

Même principe qu'en C♯ où l'on choisit comme valeurs des multiples de 2 afin de pouvoir les combiner :

💡 Notes :

  • L'attribut System.FlagsAttribute est facultatif mais permet d'avoir un code plus explicite. En outre, il améliore le rendu des combinaisons de flags : dans l'exemple précédent, la valeur affichée de permissions est Read, Write. Sans l'attribut Flags, cela aurait afficher 3.

  • Opérateur OU binaire ||| (| en C♯) pour combiner des flags

💡 Astuce : utiliser la notation binaire pour la valeur des flags :

Combinaisons

En C♯, l'on peut directement combiner des flags, comme ReadWrite et All ci-dessous :

Ce n'est pas possible en F♯ mais 2 alternatives sont possibles :

1) Procéder manuellement aux combinaisons binaires : ce n'est pas dur à faire mais cela nuit à la visibilité car cela demande un peu de réflexion pour retrouver les flags initiaux. On notera aussi que ces combinaisons font partie intégrante de l'enum.

2) Utiliser un module compagnon : pour rendre les combinaisons explicites dans le code mais non reconnues / recombinées par le compilateur.

Note : la méthode HasFlag a un comportement différent selon l'option utilisée. C'est mis en valeur dans l'exemple ci-dessous définissant les 2 helpers Enum.values déjà vu plus haut et Enum.flags qui décompose une valeur d'enum en ses flags élémentaires.

Enum vs Union

Type
Enum
Union

Type sous-jacent

Entières ou char

Quelconques

Qualification

Obligatoire

Qu'en cas de conflit

Matching exhaustif

❌ Non

✅ Oui

PascalCase

✅ Oui

✅ Oui

camelCase

✅ Oui

❌ Non

Recommandation :

  • Préférer une Union dans la majorité des cas

  • Choisir une Enum pour :

    • Interop .NET

    • Besoin de lier des données de type int

Conversion

enum<'enum> : permet de convertir une valeur entière en l'enum 'enum spécifiée

int permet la conversion inverse pour récupérer la valeur sous-jacente d'un membre d'une enum

Char enum

Pour les enums dont le type sous-jacent est char, les fonctions enum, int et char ne marchent pas :

Il faut alors utiliser le module LanguagePrimitives :

Extras

Le package NuGet FSharpx.Extras comporte un module Enum proposant ces helpers :

  • parse<'enum>: string -> 'enum

  • tryParse<'enum>: string -> 'enum option

  • getValues<'enum>: unit -> 'enum seq

Mis à jour

Ce contenu vous a-t-il été utile ?