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 i
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'.
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;
}
}
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)
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))
{
// ...
}
How about
if ((letter & Letters.AB) > 0)
?
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;
}