Pour la vie de moi, je ne me souviens pas comment définir, supprimer, basculer ou tester un peu dans un champ de bits. Soit je ne suis pas sûr, soit je les mélange parce que j'en ai rarement besoin. Donc, un "bit-cheat-sheet" serait bien d'avoir.
Par exemple:
flags = flags | FlagsEnum.Bit4; // Set bit 4.
ou
if ((flags & FlagsEnum.Bit4)) == FlagsEnum.Bit4) // Is there a less verbose way?
Pouvez-vous donner des exemples de toutes les autres opérations courantes, de préférence dans la syntaxe C # en utilisant une énumération [Flags]?
Réponses:
J'ai fait un peu plus de travail sur ces extensions - Vous pouvez trouver le code ici
J'ai écrit quelques méthodes d'extension qui étendent System.Enum que j'utilise souvent ... Je ne prétends pas qu'elles sont à l'épreuve des balles, mais elles ont aidé ... Commentaires supprimés ...
Ensuite, ils sont utilisés comme suit
la source
HasFlag
méthodeEnum
nécessite la boxe.Dans .NET 4, vous pouvez maintenant écrire:
la source
FlagsEnum
soit un nom moche. :)[Flags]
doivent avoir des noms pluralisés, de sorte que le nomFlagsEnum
présente des problèmes encore plus graves que la laideur.L'idiome est d'utiliser l'opérateur au niveau du bit ou égal pour définir les bits:
Pour effacer un peu, l'idiome est d'utiliser au niveau du bit et avec négation:
Parfois, vous avez un décalage qui identifie votre bit, puis l'idiome est de les utiliser en combinaison avec le décalage à gauche:
la source
@A dessiné
Notez que, sauf dans le cas le plus simple, Enum.HasFlag comporte une lourde pénalité de performance par rapport à l'écriture manuelle du code. Considérez le code suivant:
Plus de 10 millions d'itérations, la méthode d'extension HasFlags prend 4793 ms, contre 27 ms pour l'implémentation standard au niveau du bit.
la source
HasFlag
méthode implique la boxe / unboxing, ce qui explique cette différence. Mais le coût est si insignifiant (0,4 µs) qu'à moins que vous ne soyez dans une boucle serrée, je prendrais l'appel d'API déclarative plus lisible (et moins probablement buggé) n'importe quel jour.Les opérations d'énumération des drapeaux intégrées de .NET sont malheureusement assez limitées. La plupart du temps, les utilisateurs doivent déterminer la logique de fonctionnement au niveau du bit.
Dans .NET 4, la méthode a
HasFlag
été ajoutée,Enum
ce qui permet de simplifier le code de l'utilisateur, mais malheureusement, il présente de nombreux problèmes.HasFlag
n'est pas de type sécurisé car il accepte tout type d'argument de valeur enum, pas seulement le type d'énumération donné.HasFlag
est ambigu quant à savoir s'il vérifie si la valeur a tout ou partie des indicateurs fournis par l'argument de valeur enum. C'est tout au fait.HasFlag
est assez lent car il nécessite une boxe qui provoque des allocations et donc plus de récupérations de place.En partie à cause de la prise en charge limitée de .NET pour les énumérations d'indicateurs, j'ai écrit la bibliothèque OSS Enums.NET qui résout chacun de ces problèmes et facilite la gestion des énumérations d'indicateurs.
Vous trouverez ci-dessous certaines des opérations qu'il fournit ainsi que leurs implémentations équivalentes utilisant uniquement le framework .NET.
Combiner les drapeaux
.NET
flags | otherFlags
Enums.NET
flags.CombineFlags(otherFlags)
Supprimer les drapeaux
.NET
flags & ~otherFlags
Enums.NET
flags.RemoveFlags(otherFlags)
Drapeaux communs
.NET
flags & otherFlags
Enums.NET
flags.CommonFlags(otherFlags)
Basculer les drapeaux
.NET
flags ^ otherFlags
Enums.NET
flags.ToggleFlags(otherFlags)
A tous les drapeaux
.NET
(flags & otherFlags) == otherFlags
ouflags.HasFlag(otherFlags)
Enums.NET
flags.HasAllFlags(otherFlags)
A des drapeaux
.NET
(flags & otherFlags) != 0
Enums.NET
flags.HasAnyFlags(otherFlags)
Obtenez des drapeaux
.NET
Enums.NET
flags.GetFlags()
J'essaie d'obtenir ces améliorations incorporées dans .NET Core et peut-être éventuellement le .NET Framework complet. Vous pouvez consulter ma proposition ici .
la source
Syntaxe C ++, en supposant que le bit 0 est LSB, en supposant que les drapeaux ne sont pas longs:
Vérifiez si défini:
Vérifiez si non défini:
Ensemble:
Clair:
Basculer:
la source
Pour les meilleures performances et zéro déchets, utilisez ceci:
la source
Pour tester un peu, vous devez procéder comme suit: (en supposant que les drapeaux sont un nombre de 32 bits)
Bit de test:
(Si le bit 4 est défini, il est vrai) Basculer vers l'arrière (1 - 0 ou 0 - 1): Remettre le bit 4 à zéro:la source
~0x08
au lieu de0xFFFFFFF7
... (le masque réel pour 0x8)Cela a été inspiré par l'utilisation de Sets comme indexeurs dans Delphi, il y a longtemps:
la source
Les opérations C ++ sont: & | ^ ~ (pour les opérations et, ou, xor et non au niveau du bit). Sont également intéressants >> et <<, qui sont des opérations de décalage de bits.
Donc, pour tester la présence d'un bit dans un drapeau, vous utiliseriez: if (flags & 8) // teste le bit 4 a été défini
la source