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 d'indicateur combinée est défini par rapport au suivant?
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 binaires comme ça ...
Si vous voulez savoir si une lettre a une de ces lettres dans AB, vous devez utiliser l'opérateur ET &. 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 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<T>(bool withFlags)
{
if (!typeof(T).IsEnum)
throw new ArgumentException(string.Format("Type '{0}' is not an enum", typeof(T).FullName));
if (withFlags && !Attribute.IsDefined(typeof(T), typeof(FlagsAttribute)))
throw new ArgumentException(string.Format("Type '{0}' doesn't have the 'Flags' attribute", typeof(T).FullName));
}
public static bool IsFlagSet<T>(this T value, T flag) where T : struct
{
CheckIsEnum<T>(true);
long lValue = Convert.ToInt64(value);
long lFlag = Convert.ToInt64(flag);
return (lValue & lFlag) != 0;
}
public static IEnumerable<T> GetFlags<T>(this T value) where T : struct
{
CheckIsEnum<T>(true);
foreach (T flag in Enum.GetValues(typeof(T)).Cast<T>())
{
if (value.IsFlagSet(flag))
yield return flag;
}
}
public static T SetFlags<T>(this T value, T flags, bool on) where T : struct
{
CheckIsEnum<T>(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<T>(this T value, T flags) where T : struct
{
return value.SetFlags(flags, true);
}
public static T ClearFlags<T>(this T value, T flags) where T : struct
{
return value.SetFlags(flags, false);
}
public static T CombineFlags<T>(this IEnumerable<T> flags) where T : struct
{
CheckIsEnum<T>(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 string GetDescription<T>(this T value) where T : struct
{
CheckIsEnum<T>(false);
string name = Enum.GetName(typeof(T), value);
if (name != null)
{
FieldInfo field = typeof(T).GetField(name);
if (field != null)
{
DescriptionAttribute attr = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute;
if (attr != null)
{
return attr.Description;
}
}
}
return null;
}
}
Il existe une méthode HasFlag dans .NET 4 ou supérieure.
if(letter.HasFlag(Letters.AB))
{
}
Si vous pouvez utiliser .NET 4 ou une version ultérieure, utilisez 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 ((letter & Letters.AB) == Letters.AB)
Existe-t-il un moyen plus simple de vérifier si l'un des indicateurs d'une constante d'indicateur combinée est défini par rapport au suivant?
Ceci 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)
Ceci vérifie que soit A ou B est défini, et ignore si d'autres indicateurs sont définis ou non.
Ceci peut être simplifié pour:
if(letter & Letters.AB)
Voici le C pour les opérations binaires; il devrait être simple de l'appliquer à 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, la dénomination de la variable dans l'exemple de la question est la "lettre" singulière, ce qui pourrait impliquer qu'elle ne représente qu'une seule lettre; L'exemple de code indique clairement qu'il s'agit d'un ensemble de lettres possibles et que plusieurs valeurs sont autorisées. Il est donc conseillé de renommer la variable 'lettres'.
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);
}
Cela fonctionne également sur les énumérations nullables. La méthode standard HasFlag
ne fonctionne pas, alors j'ai créé une extension pour couvrir cela aussi.
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!
Que diriez-vous
if ((letter & Letters.AB) > 0)
?
Est-ce que cela fonctionnerait pour vous?
if ((letter & (Letters.A | Letters.B)) != 0)
Cordialement,
Sebastiaan
Il y a beaucoup de réponses ici mais je pense que la manière la plus idiomatique de faire cela avec Flags serait Letters.AB.HasFlag (lettre) ou (Letters.A | Letters.B) .HasFlag (lettre) si vous ne le faites pas avez déjà Letters.AB. letter.HasFlag (Letters.AB) ne fonctionne que s'il possède les deux.
Désolé, mais je vais le montrer dans VB :)
<Flags()> 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ération contient 1 + 4
Vous pouvez utiliser cette méthode d'extension sur enum, pour tout type d'ensums:
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;
}
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 que la meilleure solution consiste à introduire une nouvelle valeur d’énumération avec la valeur zéro et à comparer cette valeur d’énumération (si possible car 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) { }
MISE À JOUR
Erreur de lecture de la question - corrige la première suggestion et ignore simplement la seconde.
Je peux voir qu'il y a deux approches qui fonctionneraient pour vérifier si un bit est défini.
aproach A
if (letter != 0)
{
}
Cela fonctionne tant que vous n'avez pas peur de vérifier tous les bits, y compris ceux qui ne sont pas 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 jeux), utilisez Aproach B en remplaçant Letters.All par les bits que vous souhaitez vérifier (voir ci-dessous).
if ((letter & Letters.AB) != 0)
{
}