Disons que j'ai ce qui suit
int susan = 2; //0010
int bob = 4; //0100
int karen = 8; //1000
et je passe 10 (8 + 2) comme paramètre à une méthode et je veux décoder cela pour signifier susan et karen
Je sais que 10 est 1010
mais comment puis-je faire de la logique pour voir si un bit spécifique est vérifié comme dans
if (condition_for_karen) // How to quickly check whether effective karen bit is 1
Pour le moment, tout ce que je peux penser est de vérifier si le numéro que j'ai passé est
14 // 1110
12 // 1100
10 // 1010
8 // 1000
Lorsque j'ai un plus grand nombre de bits réels dans mon scénario du monde réel, cela semble peu pratique, quelle est la meilleure façon d'utiliser un masque pour simplement vérifier si je remplis ou non la condition pour juste karen?
Je peux penser à passer à gauche, puis à revenir à droite, puis à revenir à des bits clairs autres que celui qui m'intéresse, mais cela semble aussi trop complexe.
Réponses:
La manière traditionnelle de procéder consiste à utiliser l'
Flags
attribut sur unenum
:Ensuite, vous vérifieriez un nom particulier comme suit:
Les combinaisons logiques au niveau du bit peuvent être difficiles à retenir, donc je me simplifie la vie avec une
FlagsHelper
classe *:Cela me permettrait de réécrire le code ci-dessus comme suit:
Notez que je pourrais également ajouter
Karen
à l'ensemble en faisant ceci:Et je pourrais supprimer
Susan
de la même manière:* Comme Porges a souligné, un équivalent de la
IsSet
méthode ci - dessus existe déjà dans .NET 4.0:Enum.HasFlag
. LesSet
etUnset
méthodes ne semblent pas avoir équivalents, cependant; alors je dirais toujours que cette classe a du mérite.Remarque: l'utilisation d'énumérations n'est que la manière conventionnelle de résoudre ce problème. Vous pouvez totalement traduire tout le code ci-dessus pour utiliser ints à la place et cela fonctionnera tout aussi bien.
la source
(names & Names.Susan) == Names.Susan
, ce qui ne nécessite pas de fichierNone
.None
valeur pour toutes mes énumérations, car je trouve que cela finit par être pratique dans de nombreux scénarios.var susanIsIncluded = names.HasFlag(Names.Susan);
Set
méthode. Donc, je dirais que les méthodes d'assistance ne sont au moins pas totalement sans valeur.)names.HasFlag(Names.Susan)
est comme(names & Names.Susan) == Names.Susan
ce qui n'est pas toujours comme(names & Names.Susan) != Names.None
. Par exemple, si vous vérifiez sinames.HasFlag(Names.none)
ounames.HasFlag(Names.Susan|Names.Karen)
Le bit "et" masquera tout sauf le bit qui "représente" Karen. Tant que chaque personne est représentée par une seule position de bit, vous pouvez vérifier plusieurs personnes avec un simple:
la source
J'ai inclus un exemple ici qui montre comment vous pourriez stocker le masque dans une colonne de base de données en tant qu'int, et comment vous rétabliriez le masque plus tard:
la source
Pour combiner des masques de bits, vous souhaitez utiliser au niveau du bit ou . Dans le cas trivial où chaque valeur que vous combinez a exactement 1 bit (comme votre exemple), cela équivaut à les ajouter. Si vous avez des bits qui se chevauchent cependant, ou 'ing les gère le cas avec élégance.
Pour décoder les bitmasks vous et votre valeur avec un masque, comme ceci:
la source
Moyen facile:
Pour définir les indicateurs, utilisez l'opérateur logique "ou"
|
:Et pour vérifier si un drapeau est inclus, utilisez
HasFlag
:la source
HasFlag()
et des[Flags]
n'a pas été fourni dans les autres réponses.Une autre très bonne raison d'utiliser un masque de bits par rapport à des bools individuels est en tant que développeur Web, lors de l'intégration d'un site Web à un autre, nous devons fréquemment envoyer des paramètres ou des indicateurs dans la chaîne de requête. Tant que tous vos indicateurs sont binaires, il est beaucoup plus simple d'utiliser une seule valeur comme masque de bits que d'envoyer plusieurs valeurs sous forme de booléens. Je sais qu'il existe d'autres moyens d'envoyer des données (GET, POST, etc.), mais un simple paramètre sur la chaîne de requête est la plupart du temps suffisant pour les éléments non sensibles. Essayez d'envoyer 128 valeurs booléennes sur une chaîne de requête pour communiquer avec un site externe. Cela donne également la possibilité supplémentaire de ne pas repousser la limite des chaînes de requête d'URL dans les navigateurs
la source