Énumérations avec FlagsAttribute

FlagsAttribute appliqué à une énumération permet de combiner plusieurs valeurs de cette énumérations. Rien de nouveau pour vous (sinon, voir MSDN).

Mais de quelle façon définissez-vous les valeurs ?


[Flags]
public enum MyFlags
{
    Flag1 = 0x01,  // 00001
    Flag2 = 0x02,  // 00010
    Flag3 = 0x04,  // 00100
    Flag4 = 0x08,  // 01000
    Flag5 = 0x10   // 10000
}

Jusqu’à présent, j’avais l’habitude d’utiliser la notation ci-dessus, qui est équivalente à celle-ci:

[Flags]
public enum MyFlags
{
    Flag1 = 1,
    Flag2 = 2,
    Flag3 = 4,
    Flag4 = 8,
    Flag5 = 16,
}

Lorsque l’énumération est susceptible de contenir beaucoup de valeurs, aucune de ces notations n’est vraiment très pratique pour éviter une erreur.

En lisant un bouquin sur le langage C (bon ok, sur Objective-C… (c’était avant l’annonce de SWIFT, sinon vous pensez bien que j’aurai économisé mon temps)), je suis tombé sur un exemple de code avec cette notation:

[Flags]
public enum MyFlags
{
    Flag1 = 1 << 0,
    Flag2 = 1 << 1,
    Flag3 = 1 << 2,
    Flag4 = 1 << 3,
    Flag5 = 1 << 4,
}

N’est-ce pas beaucoup plus clair ? Il est ainsi très simple d’éviter une collision entre deux valeurs (il n’y a qu’à suivre la séquence de 1 en 1). Je ne découvre pas l’opérateur de bits << mais je n’ai tout bêtement jamais pensé à l’utiliser ainsi.

Après avoir remarqué cela, j’ai rapidement cherché sur le net des articles de référence sur les énumérations et les flags en C#, je ne trouve aucun exemple de code qui utilise cette notation. Il m’a donc semblé bon de faire ce petit article qui pourra peut-être servir à d’autres développeurs aussi paresseux que moi dès qu’il s’agit de faire des maths…

[Flags]
public enum MyFlags
{
    Flag1 = 1 << 0,
    Flag2 = 1 << 1,
    Flag3 = 1 << 2,
    Flag4 = 1 << 3,
    Flag5 = 1 << 4,
}

public class Program
{
    public void Main()
    {
        var flags = MyFlags.Flag1 | MyFlags.Flag3;
        Console.WriteLine("Flags: {0}\r\n{1}", flags, ConvertToBitString((int)flags));
    }

    static string ConvertToBitString(int n)
    {
        var buffer = new char[32];
        var index = 31;
        int i = -1;
        while (++i < 32)
        {
            buffer[index] = (n & (1 << i)) != 0 ? '1' : '0';
            index--;
        }
        return new string(buffer);
    }
}

/* Output:

Flags: Value1, Value3
00000000000000000000000000000101
*/