可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
Let's say I have this enum:
[Flags] enum Letters { A = 1, B = 2, C = 4, AB = A | B, All = A | B | C, }
To check if for example AB is set I can do this:
if((letter & Letters.AB) == Letters.AB)
Is there a simpler way to check if any of the flags of a combined flag constant are set than the following?
if((letter & Letters.A) == Letters.A || (letter & Letters.B) == Letters.B)
Could you for example swap the & with something?
Not too stable when it comes to binary stuff like this...
回答1:
If you want to know if letter has any of the letters in AB you must use the AND & operator. Something like:
if ((letter & Letters.AB) != 0) { // Some flag (A,B or both) is enabled } else { // None of them are enabled }
回答2:
In .NET 4 you can use the Enum.HasFlag method :
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); } }
The example displays the following output:
// 1 of 3 families in the sample have no pets. // 2 of 3 families in the sample have a dog.
回答3:
I use extension methods to write things like that :
if (letter.IsFlagSet(Letter.AB)) ...
Here's the 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; } }
回答4:
There is HasFlag method in .NET 4 or higher.
if(letter.HasFlag(Letters.AB)) { }
回答5:
If you can use .NET 4 or higher than use HasFlag() method
examples
letter.HasFlag(Letters.A | Letters.B) // both A and B must be set
same as
letter.HasFlag(Letters.AB)
回答6:
If it really annoys you, you can write a function like that:
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)) { // ... }
回答7:
To check if for example AB is set I can do this:
if((letter & Letters.AB) == Letters.AB)
Is there a simpler way to check if any of the flags of a combined flag constant are set than the following?
This checks that both A and B are set, and ignores whether any other flags are set.
if((letter & Letters.A) == Letters.A || (letter & Letters.B) == Letters.B)
This checks that either A or B is set, and ignores whether any other flags are set or not.
This can be simplified to:
if(letter & Letters.AB)
Here's the C for binary operations; it should be straightforward to apply this to 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));
Incidentally, the naming of the variable in the question's example is the singular 'letter', which might imply that it represents only a single letter; the example code makes it clear that its a set of possible letters and that multiple values are allowed, so consider renaming the variable 'letters'.
回答8:
How about
if ((letter & Letters.AB) > 0)
?
回答9:
Would this work for you?
if ((letter & (Letters.A | Letters.B)) != 0)
Regards,
Sebastiaan
回答10:
There are a lot of answers on here but I think the most idiomatic way to do this with Flags would be Letters.AB.HasFlag(letter) or (Letters.A | Letters.B).HasFlag(letter) if you didn't already have Letters.AB. letter.HasFlag(Letters.AB) only works if it has both.
回答11:
I created a simple extension method that does not need a check on Enum types:
public static bool HasAnyFlag(this Enum value, Enum flags) { return value != null && ((Convert.ToInt32(value) & Convert.ToInt32(flags)) != 0); }
It also works on nullable enums. The standard HasFlag method does not, so I created an extension to cover that too.
public static bool HasFlag(this Enum value, Enum flags) { int f = Convert.ToInt32(flags); return value != null && ((Convert.ToInt32(value) & f) == f); }
A simple test:
[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)); }
Enjoy!
回答12:
回答13:
You could just check if the value is not zero.
if ((Int32)(letter & Letters.AB) != 0) { }
But I would consider it a better solution to introduce a new enumeration value with value zero and compare agains this enumeration value (if possible because you must be able to modify the enumeration).
[Flags] enum Letters { None = 0, A = 1, B = 2, C = 4, AB = A | B, All = AB | C } if (letter != Letters.None) { }
UPDATE
Missread the question - fixed the first suggestion and just ignore the second suggestion.
回答14:
There are two aproaches that I can see that would work for checking for any bit being set.
Aproach A
if (letter != 0) { }
This works as long as you don't mind checking for all bits, including non-defined ones too!
Aproach B
if ((letter & Letters.All) != 0) { }
This only checks the defined bits, as long as Letters.All represents all of the possible bits.
For specific bits (one or more set), use Aproach B replacing Letters.All with the bits that you want to check for (see below).
if ((letter & Letters.AB) != 0) { }
回答15:
Sorry, but i will show it in 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 So the enum contains 1 + 4
回答16:
You can use this extension method on enum, for any type of enums:
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; }