151 votes

Comment comparer des drapeaux en C# ?

J'ai un enum de drapeau ci-dessous.

[Flags]
public enum FlagTest
{
    None = 0x0,
    Flag1 = 0x1,
    Flag2 = 0x2,
    Flag3 = 0x4
}

Je ne peux pas faire en sorte que l'instruction if soit évaluée comme vraie.

FlagTest testItem = FlagTest.Flag1 | FlagTest.Flag2;

if (testItem == FlagTest.Flag1)
{
    // Do something,
    // however This is never true.
}

Comment puis-je faire en sorte que ce soit vrai ?

317voto

Phil Devaney Points 8595

Dans .NET 4, il existe une nouvelle méthode Enum.HasFlag . Cela vous permet d'écrire :

if ( testItem.HasFlag( FlagTest.Flag1 ) )
{
    // Do Stuff
}

qui est beaucoup plus lisible, IMO.

La source .NET indique que cela exécute la même logique que la réponse acceptée :

public Boolean HasFlag(Enum flag) {
    if (!this.GetType().IsEquivalentTo(flag.GetType())) {
        throw new ArgumentException(
            Environment.GetResourceString(
                "Argument_EnumTypeDoesNotMatch", 
                flag.GetType(), 
                this.GetType()));
    }

    ulong uFlag = ToUInt64(flag.GetValue()); 
    ulong uThis = ToUInt64(GetValue());
    // test predicate
    return ((uThis & uFlag) == uFlag); 
}

177voto

Scott Nichols Points 3366
if ((testItem & FlagTest.Flag1) == FlagTest.Flag1)
{
     // Do something
}

(testItem & FlagTest.Flag1) est une opération ET par bit.

FlagTest.Flag1 est équivalent à 001 avec l'énumération de l'OP. Disons maintenant testItem a Flag1 et Flag2 (il s'agit donc d'un traitement par bit). 101 ) :

  001
 &101
 ----
  001 == FlagTest.Flag1

78voto

Sekhat Points 2555

Pour ceux qui ont du mal à visualiser ce qui se passe avec la solution acceptée (qui est la suivante),

if ((testItem & FlagTest.Flag1) == FlagTest.Flag1)
{
    // Do stuff.
}

testItem (selon la question) est défini comme suit,

testItem 
 = flag1 | flag2  
 = 001 | 010  
 = 011

Ensuite, dans l'instruction if, le côté gauche de la comparaison est,

(testItem & flag1) 
 = (011 & 001) 
 = 001

Et l'instruction if complète (qui évalue à true si flag1 est fixé dans testItem ),

(testItem & flag1) == flag1
 = (001) == 001
 = true

21voto

Keith Points 46288

J'ai mis en place une méthode d'extension pour le faire : Question connexe .

En gros :

public static bool IsSet( this Enum input, Enum matchTo )
{
    return ( Convert.ToUInt32( input ) & Convert.ToUInt32( matchTo ) ) != 0;
}

Alors vous pouvez le faire :

FlagTests testItem = FlagTests.Flag1 | FlagTests.Flag2;

if( testItem.IsSet ( FlagTests.Flag1 ) )
    //Flag1 is set

D'ailleurs, la convention que j'utilise pour les enums est le singulier pour les standards, le pluriel pour les drapeaux. De cette façon, vous savez à partir du nom de l'enum s'il peut contenir plusieurs valeurs.

19voto

Leonid Points 181

Un autre conseil... Ne faites jamais la vérification binaire standard avec le drapeau dont la valeur est "0". Votre contrôle sur ce drapeau sera toujours vrai.

[Flags]
public enum LevelOfDetail
{
    [EnumMember(Value = "FullInfo")]
    FullInfo=0,
    [EnumMember(Value = "BusinessData")]
    BusinessData=1
}

Si vous vérifiez binairement le paramètre d'entrée par rapport à FullInfo - vous obtenez :

detailLevel = LevelOfDetail.BusinessData;
bool bPRez = (detailLevel & LevelOfDetail.FullInfo) == LevelOfDetail.FullInfo;

bPRez sera toujours vrai comme ANYTHING & 0 toujours == 0.


Au lieu de cela, vous devez simplement vérifier que la valeur de l'entrée est 0 :

bool bPRez = (detailLevel == LevelOfDetail.FullInfo);

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X