Question

De temps en temps je vois un enum comme suit:

[Flags]
public enum Options 
{
    None    = 0,
    Option1 = 1,
    Option2 = 2,
    Option3 = 4,
    Option4 = 8
}

Je ne comprends pas ce qu'est exactement le [Flags]-attribut n'.

Quelqu'un a une bonne explication ou un exemple, ils pourraient post?

Était-ce utile?

La solution

L' [Flags] attribut doit être utilisé chaque fois que l'énumérable représente un ensemble de valeurs possibles, plutôt qu'une valeur unique.Ces collections sont souvent utilisés avec les opérateurs au niveau du bit, par exemple:

var allowedColors = MyColor.Red | MyColor.Green | MyColor.Blue;

Notez que l' [Flags] attribut ne pas permettre de lui-même - il n'est de permettre une représentation de nice par l' .ToString() méthode:

enum Suits { Spades = 1, Clubs = 2, Diamonds = 4, Hearts = 8 }
[Flags] enum SuitsFlags { Spades = 1, Clubs = 2, Diamonds = 4, Hearts = 8 }

...

var str1 = (Suits.Spades | Suits.Diamonds).ToString();
           // "5"
var str2 = (SuitsFlags.Spades | SuitsFlags.Diamonds).ToString();
           // "Spades, Diamonds"

Il est également important de noter que [Flags] ne pas automatiquement faire l'énumération des valeurs des puissances de deux.Si vous omettez les valeurs numériques, l'enum ne fonctionne pas comme on pourrait s'y attendre dans les opérations bit à bit, parce que par défaut, les valeurs 0 et d'un incrément.

Fausse déclaration:

[Flags]
public enum MyColors
{
    Yellow,  // 0
    Green,   // 1
    Red,     // 2
    Blue     // 3
}

Les valeurs, en cas de déclaration de cette façon, sera Jaune = 0, Vert = 1, Rouge = 2, Bleu = 3.Cela rendra inutile comme des drapeaux.

Voici un exemple d'une déclaration correcte:

[Flags]
public enum MyColors
{
    Yellow = 1,
    Green = 2,
    Red = 4,
    Blue = 8
}

Pour récupérer les valeurs distinctes dans votre propriété, on peut faire ceci:

if (myProperties.AllowedColors.HasFlag(MyColor.Yellow))
{
    // Yellow is allowed...
}

ou avant .NET 4:

if((myProperties.AllowedColors & MyColor.Yellow) == MyColor.Yellow)
{
    // Yellow is allowed...
}

if((myProperties.AllowedColors & MyColor.Green) == MyColor.Green)
{
    // Green is allowed...
}    

Sous les couvertures

Cela fonctionne parce que vous avez utilisé des puissances de deux, dans votre énumération.Sous les couvertures, vos valeurs d'énumération ressembler à cela en binaire uns et de zéros:

 Yellow: 00000001
 Green:  00000010
 Red:    00000100
 Blue:   00001000

De même, une fois que vous avez réglé votre propriété AllowedColors pour le Rouge, le Vert et le Bleu à l'aide de la binaire OU bit-à-bit | l'opérateur, AllowedColors ressemble à ceci:

myProperties.AllowedColors: 00001110

Ainsi, lorsque vous récupérez la valeur que vous êtes en fait effectuer au niveau du bit ET & sur les valeurs:

myProperties.AllowedColors: 00001110
             MyColor.Green: 00000010
             -----------------------
                            00000010 // Hey, this is the same as MyColor.Green!

Aucune = 0 valeur

Et concernant l'utilisation de 0 dans votre énumération, citant le partir de MSDN:

[Flags]
public enum MyColors
{
    None = 0,
    ....
}

Utiliser rien que le nom de l'indicateur énumérés constante dont la valeur est égale à zéro. Vous ne pouvez pas utiliser la Aucune constante énumérée dans un bit à bit ET l'exploitation de test pour un drapeau parce que le résultat est toujours à zéro. Toutefois, vous pouvez effectuer une logique, pas un bit à bit, la comparaison entre la valeur numérique et Aucune constante énumérée à déterminer si tous les bits de la valeur numérique sont fixés.

Vous pouvez trouver plus d'informations sur l'attribut flags et de son utilisation à msdn et la conception de drapeaux sur le site msdn

Autres conseils

Vous pouvez également le faire

[Flags]
public enum MyEnum
{
    None   = 0,
    First  = 1 << 0,
    Second = 1 << 1,
    Third  = 1 << 2,
    Fourth = 1 << 3
}

Je trouve le décalage de bits plus facile que de taper 4,8,16,32 et ainsi de suite.Il n'a pas d'impact sur votre code, parce que tout est fait au moment de la compilation

En combinant les réponses https://stackoverflow.com/a/8462/1037948 (déclaration par décalage de bits) et https://stackoverflow.com/a/9117/1037948 (à l'aide de combinaisons dans la déclaration), vous pouvez décalage de bit valeurs précédentes plutôt que d'utiliser des nombres.Pas nécessairement le recommander, mais simplement en indiquant que vous le pouvez.

Plutôt que:

[Flags]
public enum Options : byte
{
    None    = 0,
    One     = 1 << 0,   // 1
    Two     = 1 << 1,   // 2
    Three   = 1 << 2,   // 4
    Four    = 1 << 3,   // 8

    // combinations
    OneAndTwo = One | Two,
    OneTwoAndThree = One | Two | Three,
}

Vous pouvez déclarer

[Flags]
public enum Options : byte
{
    None    = 0,
    One     = 1 << 0,       // 1
    // now that value 1 is available, start shifting from there
    Two     = One << 1,     // 2
    Three   = Two << 1,     // 4
    Four    = Three << 1,   // 8

    // same combinations
    OneAndTwo = One | Two,
    OneTwoAndThree = One | Two | Three,
}

Confirmation avec LinqPad:

foreach(var e in Enum.GetValues(typeof(Options))) {
    string.Format("{0} = {1}", e.ToString(), (byte)e).Dump();
}

Résultats:

None = 0
One = 1
Two = 2
OneAndTwo = 3
Three = 4
OneTwoAndThree = 7
Four = 8

Veuillez voir ci-après pour un exemple qui montre la déclaration et le potentiel d'utilisation:

namespace Flags
{
    class Program
    {
        [Flags]
        public enum MyFlags : short
        {
            Foo = 0x1,
            Bar = 0x2,
            Baz = 0x4
        }

        static void Main(string[] args)
        {
            MyFlags fooBar = MyFlags.Foo | MyFlags.Bar;

            if ((fooBar & MyFlags.Foo) == MyFlags.Foo)
            {
                Console.WriteLine("Item has Foo flag set");
            }
        }
    }
}

J' récemment posées à propos de quelque chose de similaire.

Si vous utilisez des indicateurs que vous pouvez ajouter une méthode d'extension pour les énumérations de faire vérifier le contenu des drapeaux plus facile (voir le post pour les détails)

Cela vous permet de faire:

[Flags]
public enum PossibleOptions : byte
{
    None = 0,
    OptionOne = 1,
    OptionTwo = 2,
    OptionThree = 4,
    OptionFour = 8,

    //combinations can be in the enum too
    OptionOneAndTwo = OptionOne | OptionTwo,
    OptionOneTwoAndThree = OptionOne | OptionTwo | OptionThree,
    ...
}

Ensuite, vous pouvez faire:

PossibleOptions opt = PossibleOptions.OptionOneTwoAndThree 

if( opt.IsSet( PossibleOptions.OptionOne ) ) {
    //optionOne is one of those set
}

Je trouve cela plus facile à lire que la plupart des moyens de vérification de l'compris les drapeaux.

Dans le prolongement de la accepté de répondre, en C#7 enum indicateurs peuvent être écrites à l'aide binaire de littéraux:

[Flags]
public enum MyColors
{
    None   = 0b0000,
    Yellow = 0b0001,
    Green  = 0b0010,
    Red    = 0b0100,
    Blue   = 0b1000
}

Je pense que cette représentation indique clairement la façon dont les drapeaux de travail sous les couvertures.

@Nidonocu

Pour ajouter un indicateur à un ensemble de valeurs, utilisez l'opérateur d'affectation.

Mode = Mode.Read;
//Add Mode.Write
Mode |= Mode.Write;
Assert.True(((Mode & Mode.Write) == Mode.Write)
  && ((Mode & Mode.Read) == Mode.Read)));

Pour ajouter Mode.Write:

Mode = Mode | Mode.Write;

Il y a quelque chose de trop verbeux à moi au sujet de la if ((x & y) == y)... construire, surtout si x ET y sont à la fois complexe jeux de drapeaux et vous voulez savoir si il y a tout chevauchement.

Dans ce cas, tout ce que vous devez savoir, c'est si il y a une valeur non nulle[1] une fois que vous avez bitmasked.

[1] Voir Jaime commentaire.Si nous avons été authentiquement bitmasking, nous avions seulement besoin de vérifier que le résultat a été positif.Mais depuis enums peut être négatif, même, étrangement, lorsqu'il est combiné avec l' [Flags] attribut, c'est la défensive à code pour != 0 plutôt que de > 0.

Construction de @andnil de l'installation...

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BitFlagPlay
{
    class Program
    {
        [Flags]
        public enum MyColor
        {
            Yellow = 0x01,
            Green = 0x02,
            Red = 0x04,
            Blue = 0x08
        }

        static void Main(string[] args)
        {
            var myColor = MyColor.Yellow | MyColor.Blue;
            var acceptableColors = MyColor.Yellow | MyColor.Red;

            Console.WriteLine((myColor & MyColor.Blue) != 0);     // True
            Console.WriteLine((myColor & MyColor.Red) != 0);      // False                
            Console.WriteLine((myColor & acceptableColors) != 0); // True
            // ... though only Yellow is shared.

            Console.WriteLine((myColor & MyColor.Green) != 0);    // Wait a minute... ;^D

            Console.Read();
        }
    }
}

Drapeaux de vous permettre d'utiliser bitmasking à l'intérieur de votre énumération.Cela vous permet de combiner des valeurs d'énumération, tout en conservant celles qui sont spécifiées.

[Flags]
public enum DashboardItemPresentationProperties : long
{
    None = 0,
    HideCollapse = 1,
    HideDelete = 2,
    HideEdit = 4,
    HideOpenInNewWindow = 8,
    HideResetSource = 16,
    HideMenu = 32
}

Lorsque vous travaillez avec des drapeaux, j'ai souvent déclarer supplémentaire Aucun et Tous les éléments.Ceux-ci sont utiles pour vérifier si tous les drapeaux sont ensemble ou pas de drapeau est réglé.

[Flags] 
enum SuitsFlags { 

    None =     0,

    Spades =   1 << 0, 
    Clubs =    1 << 1, 
    Diamonds = 1 << 2, 
    Hearts =   1 << 3,

    All =      ~(~0 << 4)

}

Utilisation:

Spades | Clubs | Diamonds | Hearts == All  // true
Spades & Clubs == None  // true
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top