Comment vérifier si des indicateurs d’une combinaison de drapeaux sont définis?

Disons que j’ai cette énumération:

[Flags] enum Letters { A = 1, B = 2, C = 4, AB = A | B, All = A | B | C, } 

Pour vérifier si, par exemple, AB est défini, je peux le faire:

 if((letter & Letters.AB) == Letters.AB) 

Existe-t-il un moyen plus simple de vérifier si l’un des indicateurs d’une constante de drapeau combiné est défini comme suit?

 if((letter & Letters.A) == Letters.A || (letter & Letters.B) == Letters.B) 

Pourriez-vous par exemple échanger le & avec quelque chose?

Pas trop stable quand il s’agit de choses binarys comme ça …

Si vous voulez savoir si la lettre a l’une des lettres en AB, vous devez utiliser l’opérateur AND &. Quelque chose comme:

 if ((letter & Letters.AB) != 0) { // Some flag (A,B or both) is enabled } else { // None of them are enabled } 

Dans .NET 4, vous pouvez utiliser la méthode Enum.HasFlag :

 using System; [Flags] public enum Pet { None = 0, Dog = 1, Cat = 2, Bird = 4, Rabbit = 8, Other = 16 } public class Example { public static void Main() { // Define three families: one without pets, one with dog + cat and one with a dog only Pet[] petsInFamilies = { Pet.None, Pet.Dog | Pet.Cat, Pet.Dog }; int familiesWithoutPets = 0; int familiesWithDog = 0; foreach (Pet petsInFamily in petsInFamilies) { // Count families that have no pets. if (petsInFamily.Equals(Pet.None)) familiesWithoutPets++; // Of families with pets, count families that have a dog. else if (petsInFamily.HasFlag(Pet.Dog)) familiesWithDog++; } Console.WriteLine("{0} of {1} families in the sample have no pets.", familiesWithoutPets, petsInFamilies.Length); Console.WriteLine("{0} of {1} families in the sample have a dog.", familiesWithDog, petsInFamilies.Length); } } 

L’exemple affiche la sortie suivante:

 // 1 of 3 families in the sample have no pets. // 2 of 3 families in the sample have a dog. 

J’utilise des méthodes d’extension pour écrire des choses comme ça:

 if (letter.IsFlagSet(Letter.AB)) ... 

Voici le code:

 public static class EnumExtensions { private static void CheckIsEnum(bool withFlags) { if (!typeof(T).IsEnum) throw new ArgumentException(ssortingng.Format("Type '{0}' is not an enum", typeof(T).FullName)); if (withFlags && !Atsortingbute.IsDefined(typeof(T), typeof(FlagsAtsortingbute))) throw new ArgumentException(ssortingng.Format("Type '{0}' doesn't have the 'Flags' atsortingbute", typeof(T).FullName)); } public static bool IsFlagSet(this T value, T flag) where T : struct { CheckIsEnum(true); long lValue = Convert.ToInt64(value); long lFlag = Convert.ToInt64(flag); return (lValue & lFlag) != 0; } public static IEnumerable GetFlags(this T value) where T : struct { CheckIsEnum(true); foreach (T flag in Enum.GetValues(typeof(T)).Cast()) { if (value.IsFlagSet(flag)) yield return flag; } } public static T SetFlags(this T value, T flags, bool on) where T : struct { CheckIsEnum(true); long lValue = Convert.ToInt64(value); long lFlag = Convert.ToInt64(flags); if (on) { lValue |= lFlag; } else { lValue &= (~lFlag); } return (T)Enum.ToObject(typeof(T), lValue); } public static T SetFlags(this T value, T flags) where T : struct { return value.SetFlags(flags, true); } public static T ClearFlags(this T value, T flags) where T : struct { return value.SetFlags(flags, false); } public static T CombineFlags(this IEnumerable flags) where T : struct { CheckIsEnum(true); long lValue = 0; foreach (T flag in flags) { long lFlag = Convert.ToInt64(flag); lValue |= lFlag; } return (T)Enum.ToObject(typeof(T), lValue); } public static ssortingng GetDescription(this T value) where T : struct { CheckIsEnum(false); ssortingng name = Enum.GetName(typeof(T), value); if (name != null) { FieldInfo field = typeof(T).GetField(name); if (field != null) { DescriptionAtsortingbute attr = Atsortingbute.GetCustomAtsortingbute(field, typeof(DescriptionAtsortingbute)) as DescriptionAtsortingbute; if (attr != null) { return attr.Description; } } } return null; } } 

Il existe une méthode HasFlag dans .NET 4 ou supérieur.

 if(letter.HasFlag(Letters.AB)) { } 

Si vous pouvez utiliser .NET 4 ou supérieur à la méthode HasFlag ()

exemples

 letter.HasFlag(Letters.A | Letters.B) // both A and B must be set 

pareil que

 letter.HasFlag(Letters.AB) 

Si cela vous ennuie vraiment, vous pouvez écrire une fonction comme celle-ci:

 public bool IsSet(Letters value, Letters flag) { return (value & flag) == flag; } if (IsSet(letter, Letters.A)) { // ... } // If you want to check if BOTH Letters.A and Letters.B are set: if (IsSet(letter, Letters.A & Letters.B)) { // ... } // If you want an OR, I'm afraid you will have to be more verbose: if (IsSet(letter, Letters.A) || IsSet(letter, Letters.B)) { // ... } 

Pour vérifier si, par exemple, AB est défini, je peux le faire:

if ((lettre & Letters.AB) == Letters.AB)

Existe-t-il un moyen plus simple de vérifier si l’un des indicateurs d’une constante de drapeau combiné est défini comme suit?

Cela vérifie que les deux A et B sont définis et ignore si d’autres indicateurs sont définis.

 if((letter & Letters.A) == Letters.A || (letter & Letters.B) == Letters.B) 

Cela vérifie que A ou B est défini et ignore si d’autres indicateurs sont définis ou non.

Cela peut être simplifié pour:

 if(letter & Letters.AB) 

Voici le C pour les opérations binarys; il devrait être simple d’appliquer ceci à C #:

 enum { A = 1, B = 2, C = 4, AB = A | B, All = AB | C, }; int flags = A|C; bool anything_and_a = flags & A; bool only_a = (flags == A); bool a_and_or_c_and_anything_else = flags & (A|C); bool both_ac_and_anything_else = (flags & (A|C)) == (A|C); bool only_a_and_c = (flags == (A|C)); 

Incidemment, le nom de la variable dans l’exemple de la question est le singulier «lettre», ce qui pourrait impliquer qu’il ne représente qu’une seule lettre; L’exemple de code indique clairement que c’est un ensemble de lettres possibles et que plusieurs valeurs sont autorisées, alors envisagez de renommer la variable “lettres”.

Que diriez-vous

 if ((letter & Letters.AB) > 0) 

?

Est-ce que cela fonctionnerait pour vous?

 if ((letter & (Letters.A | Letters.B)) != 0) 

Cordialement,

Sebastiaan

J’ai créé une méthode d’extension simple qui ne nécessite pas de vérification sur les types Enum :

 public static bool HasAnyFlag(this Enum value, Enum flags) { return value != null && ((Convert.ToInt32(value) & Convert.ToInt32(flags)) != 0); } 

Il fonctionne également sur les énumérations nulles. La méthode HasFlag standard ne fonctionne pas, alors j’ai créé une extension pour couvrir cela.

 public static bool HasFlag(this Enum value, Enum flags) { int f = Convert.ToInt32(flags); return value != null && ((Convert.ToInt32(value) & f) == f); } 

Un test simple:

 [Flags] enum Option { None = 0x00, One = 0x01, Two = 0x02, Three = One | Two, Four = 0x04 } [TestMethod] public void HasAnyFlag() { Option o1 = Option.One; Assert.AreEqual(true, o1.HasAnyFlag(Option.Three)); Assert.AreEqual(false, o1.HasFlag(Option.Three)); o1 |= Option.Two; Assert.AreEqual(true, o1.HasAnyFlag(Option.Three)); Assert.AreEqual(true, o1.HasFlag(Option.Three)); } [TestMethod] public void HasAnyFlag_NullableEnum() { Option? o1 = Option.One; Assert.AreEqual(true, o1.HasAnyFlag(Option.Three)); Assert.AreEqual(false, o1.HasFlag(Option.Three)); o1 |= Option.Two; Assert.AreEqual(true, o1.HasAnyFlag(Option.Three)); Assert.AreEqual(true, o1.HasFlag(Option.Three)); } 

Prendre plaisir!

Il y a beaucoup de réponses ici, mais je pense que la manière la plus idiomatique de le faire avec les drapeaux serait Letters.AB.HasFlag (letter) ou (Letters.A | Letters.B) .HasFlag (letter) si vous ne l’avez pas fait déjà des lettres.AB. lettre.HasFlag (Letters.AB) ne fonctionne que si elle a les deux.

 if((int)letter != 0) { } 

Vous pouvez simplement vérifier si la valeur n’est pas zéro.

 if ((Int32)(letter & Letters.AB) != 0) { } 

Mais je considérerais comme une meilleure solution d’introduire une nouvelle valeur d’énumération avec la valeur zéro et de comparer cette valeur d’énumération (si possible parce que vous devez pouvoir modifier l’énumération).

 [Flags] enum Letters { None = 0, A = 1, B = 2, C = 4, AB = A | B, All = AB | C } if (letter != Letters.None) { } 

METTRE À JOUR

Lisez mal la question – corrigez la première suggestion et ignorez simplement la deuxième suggestion.

Il y a deux approches que je peux voir qui fonctionneraient pour vérifier n’importe quel bit étant défini.

Aproach A

 if (letter != 0) { } 

Cela fonctionne aussi longtemps que vous ne craignez pas de vérifier tous les bits, y compris ceux non définis!

Aproach B

 if ((letter & Letters.All) != 0) { } 

Cela ne vérifie que les bits définis, tant que Letters.All représente tous les bits possibles.

Pour des bits spécifiques (un ou plusieurs ensembles), utilisez Aproach B en remplaçant Letters.All avec les bits que vous souhaitez vérifier (voir ci-dessous).

 if ((letter & Letters.AB) != 0) { } 

Désolé, mais je vais le montrer dans VB 🙂

   Public Enum Cnt As Integer None = 0 One = 1 Two = 2 Three = 4 Four = 8 End Enum Sub Test() Dim CntValue As New Cnt CntValue += Cnt.One CntValue += Cnt.Three Console.WriteLine(CntValue) End Sub 

CntValue = 5 Donc l’énum contient 1 + 4

Vous pouvez utiliser cette méthode d’extension sur enum, pour tout type d’énumération:

 public static bool IsSingle(this Enum value) { var items = Enum.GetValues(value.GetType()); var counter = 0; foreach (var item in items) { if (value.HasFlag((Enum)item)) { counter++; } if (counter > 1) { return false; } } return true; }