Comment supprimer un élément pour une énumération OR?

181

J'ai une énumération comme:

public enum Blah
{
    RED = 2,
    BLUE = 4,
    GREEN = 8,
    YELLOW = 16
}

Blah colors = Blah.RED | Blah.BLUE | Blah.YELLOW;

Comment puis-je supprimer la couleur bleue des couleurs variables?

Blankman
la source
2
Petite note: une énumération binaire en C # devrait avoir l'attribut [Flags] au-dessus.
Nyerguds
@Nyerguds, pourriez-vous expliquer pourquoi il devrait obtenir l'attribut?
éthane
Il offre une meilleure prise en charge d'IntelliSense lors du débogage, car il reconnaît les valeurs d'énumération inconnues comme des combinaisons de valeurs existantes.
Nyerguds
1
Il fournit également une .ToString()valeur plus significative . par exemple RED, BLUE, YELLOWplutôt que 22.
Sinjai

Réponses:

331

Vous en avez besoin &avec le ~(complément) de 'BLUE'.

L'opérateur de complément inverse ou «retourne» essentiellement tous les bits pour le type de données donné. En tant que tel, si vous utilisez l' ANDopérateur ( &) avec une valeur (appelons cette valeur `` X '') et le complément d'un ou plusieurs bits définis (appelons ces bits Qet leur complément ~Q), l'instruction X & ~Qefface tous les bits définis dans Qfrom Xet renvoie le résultat.

Donc, pour supprimer ou effacer les BLUEbits, vous utilisez l'instruction suivante:

colorsWithoutBlue = colors & ~Blah.BLUE
colors &= ~Blah.BLUE // This one removes the bit from 'colors' itself

Vous pouvez également spécifier plusieurs bits à effacer, comme suit:

colorsWithoutBlueOrRed = colors & ~(Blah.BLUE | Blah.RED)
colors &= ~(Blah.BLUE | Blah.RED) // This one removes both bits from 'colors' itself

ou alternativement ...

colorsWithoutBlueOrRed = colors & ~Blah.BLUE & ~Blah.RED
colors &= ~Blah.BLUE & ~Blah.RED // This one removes both bits from 'colors' itself

Donc pour résumer:

  • X | Q définit le (s) bit (s) Q
  • X & ~Q efface le (s) bit (s) Q
  • ~X retourne / inverse tous les bits de X
SLaks
la source
1
donc si je voulais en supprimer plus, je ferais simplement: & = ~ Blah.BLUE & ~ Blah.Green?
Blankman
11
Better iscolors &= ~( Blah.BLUE | Blah.GREEN );
par
2
Comme c'est inhabituel, je pensais juste comment faire cela il y a encore environ 5 jours :) Cette question a été mise à jour dans ma boîte de réception et le tour est joué!
Blankman
Très bonne réponse. Je pense que vous voulez dire "& =" pas "= &" dans vos exemples de code cependant;)
Dave Jellison
48

Les autres réponses sont correctes, mais pour supprimer spécifiquement le bleu de ce qui précède, vous écririez:

colors &= ~Blah.BLUE;
par
la source
9

And not il...............................

Blah.RED | Blah.YELLOW == 
   (Blah.RED | Blah.BLUE | Blah.YELLOW) & ~Blah.BLUE;
Daniel A. White
la source
7

J'ai pensé que cela pourrait être utile pour d'autres personnes qui ont trébuché ici comme moi.

Faites attention à la manière dont vous gérez les valeurs d'énumération que vous pourriez définir pour avoir une valeur == 0 (il peut parfois être utile d'avoir un état Inconnu ou Inactif pour une énumération). Cela pose des problèmes lors de l'utilisation de ces opérations de manipulation de bits.

Aussi lorsque vous avez des valeurs d'énumération qui sont des combinaisons d'autres puissances de 2 valeurs, par exemple

public enum Colour
{
    None = 0,  // default value
    RED = 2,
    BLUE = 4,
    GREEN = 8,
    YELLOW = 16,
    Orange = 18  // Combined value of RED and YELLOW
}

Dans ces cas, une méthode d'extension telle que celle-ci peut s'avérer utile:

public static Colour UnSet(this Colour states, Colour state)
{
    if ((int)states == 0)
        return states;

    if (states == state)
        return Colour.None;

    return states & ~state;
}

Et aussi la méthode IsSet équivilente qui gère les valeurs combinées (bien que de manière un peu hacky)

public static bool IsSet(this Colour states, Colour state)
{
    // By default if not OR'd
    if (states == state)
        return true;

    // Combined: One or more bits need to be set
    if( state == Colour.Orange )
        return 0 != (int)(states & state);

    // Non-combined: all bits need to be set
    return (states & state) == state;
}
Sverrir Sigmundarson
la source
Il me semble que la solution la plus simple est d'éviter d'utiliser 0 comme indicateur. J'ai généralement mis en place des énumérations de drapeau comme celle-ci . Je ne vois pas comment vous bénéficierez de la spécification d'un état avec une valeur de 0. Après tout, le fait est que vous pouvez vous préoccuper des noms conviviaux pour les programmeurs ( Red, Blue, Green) plutôt que des valeurs sous-jacentes, oui?
Sinjai
Avoir une entrée noneou unknownou unsetavec la valeur == 0 est dans de nombreux cas une bonne chose car vous ne pouvez pas toujours supposer qu'une valeur particulière est l'ensemble par défaut, par exemple si vous n'avez que Rouge, Bleu et Vert, allez-vous avoir Rouge comme la valeur par défaut (par exemple la valeur que l'énumération a lors de sa création ou l'utilisateur ne l'a pas modifiée?)
Sverrir Sigmundarson
Ne pouvez-vous pas simplement avoir Unset = 1 et utiliser 1, 2, 4, 8comme valeurs? Si vous avez besoin d'une valeur par défaut, c'est à cela que servent les constructeurs par défaut, non? J'aime garder les choses aussi explicites que possible pour des raisons de lisibilité, et compter sur une énumération par défaut à default(int)( 0) quand on ne lui donne pas de valeur, bien que ce soit des informations vraisemblablement connues de tout développeur, est de toute façon trop sournois à mon goût. Edit: Oh attendez, est-ce que faire Unset = 0 empêcherait quelque chose d'être Unset | Blue?
Sinjai
Vous êtes sur la bonne voie dans votre édition Sinjai, garder la valeur non définie == 0 résout en fait quelques problèmes. L'un étant ce que vous avez mentionné et l'autre étant que si vous désélectionnez toutes les valeurs d'énumération, vous n'avez pas besoin d'un cas particulier pour "Unset" s'il est mis à zéro. (par exemple, si vous Red & ~Redvous retrouvez avec zéro, vous devrez alors avoir un code pour vérifier ce cas et attribuer explicitement la Unsetvaleur)
Sverrir Sigmundarson
Je t'ai eu. Vous trouvez-vous souvent aux prises avec des drapeaux non définis?
Sinjai
2

Et xor (^)?

Étant donné que le FLAG que vous essayez de supprimer est là, cela fonctionnera. Sinon, vous devrez utiliser un &.

public enum Colour
{
    None = 0,  // default value
    RED = 2,
    BLUE = 4,
    GREEN = 8,
    YELLOW = 16,
    Orange = 18  // Combined value of RED and YELLOW
}

colors = (colors ^ Colour.RED) & colors;
user4509414
la source
1

Pour simplifier l'énumération des indicateurs et faire en sorte qu'il soit peut-être préférable de lire en évitant les multiples, nous pouvons utiliser le décalage de bits. (Extrait d'un bon article mettant fin au grand débat sur les drapeaux enum )

[FLAG]
Enum Blah
{
   RED = 1,
   BLUE = 1 << 1,
   GREEN = 1 << 2,
   YELLOW = 1 << 3
}

et aussi pour effacer tous les bits

private static void ClearAllBits()
{
    colors = colors & ~colors;
}
Matt Allen
la source
0

Vous pouvez utiliser ceci:

colors &= ~Blah.RED; 
Majid gharaei
la source