如何检查标志组合的标志是否被设置?

假设我有这个枚举:

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

要检查是否例如AB设置我可以这样做:

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

是否有一个简单的方法来检查组合标志常量的任何标志是否设置比以下?

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

你能举个例子交换&的东西吗?

不太稳定,当涉及到这样的二进制文件…

如果您想知道信件中是否有AB中的任何字母,则必须使用AND &运算符。 就像是:

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

在.NET 4中,您可以使用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); } } 

该示例显示以下输出:

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

我使用扩展方法来写这样的东西:

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

代码如下:

 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; } } 

在.NET 4或更高版本中有HasFlag方法。

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

如果您可以使用.NET 4或更高版本使用HasFlag()方法

例子

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

与…一样

 letter.HasFlag(Letters.AB) 

如果真的让你烦恼,你可以写一个这样的函数:

 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)) { // ... } 

要检查是否例如AB设置我可以这样做:

如果((letter&Letters.AB)== Letters.AB)

是否有一个简单的方法来检查组合标志常量的任何标志是否设置比以下?

这将检查A和B是否均置位,并忽略是否设置了其他标志。

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

这将检查是否设置了A或B,并忽略是否设置了其他标志。

这可以简化为:

 if(letter & Letters.AB) 

这里是二进制操作的C; 它应该是直接应用于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)); 

顺便提一句,在问题的例子中,variables的命名是单数的“字母”,这可能意味着它只代表一个字母; 示例代码清楚地表明它是一组可能的字母,并且允许多个值,所以考虑重命名variables“字母”。

怎么样

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

这会为你工作吗?

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

问候,

Sebastiaan

这里有很多答案,但我认为用Flags做这个最习惯的方法是Letters.AB.HasFlag(letter)或(Letters.A | Letters.B).HasFlag(letter)如果你没有已经有Letters.AB。 letter.HasFlag(Letters.AB)只有在同时有效时才有效。

我创build了一个简单的扩展方法,不需要检查Enumtypes:

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

它也适用于可空的枚举。 标准的HasFlag方法没有,所以我创build了一个扩展来覆盖。

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

一个简单的testing:

 [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)); } 

请享用!

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

你可以检查这个值是不是零。

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

但我认为这是一个更好的解决scheme,引入一个新的枚举值为零,并再次比较枚举值(如果可能,因为您必须能够修改枚举)。

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

UPDATE

错误的问题 – 解决了第一个build议,而忽略了第二个build议。

我可以看到有两个方法可以用来检查设置的位。

Aproach A

 if (letter != 0) { } 

只要你不介意检查所有的位,包括没有定义的位,就可以工作。

方法B

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

这只会检查定义的位,只要Letters.All表示所有可能的位。

对于特定的位(一个或多个集合),使用Aproach BreplaceLetters.All与您要检查的位(见下文)。

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

对不起,但我会在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所以枚举包含1 + 4

你可以在枚举上使用这个扩展方法,用于任何types的枚举:

 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; }