Given the enum
:
[Flags]
public enum mytest
{
a = 1,
b = 2,
c = 4
}
I\'ve come up with two ways to represent all va
If it makes sense to have an All
member, just provide it directly:
[Flags]
public enum mytest
{
a = 1,
b = 2,
c = 4,
All = 7
}
Though, a more idiomatic way to write these could be:
[Flags]
public enum MyTest
{
A = 1,
B = 1 << 0x01,
C = 1 << 0x02,
All = A | B | C
}
This shows the logical progression of the enum values, and in the All
case, makes it easy to add another member.
For a generic method, use Linq's Enumerable.Aggregate extension method;
var flags = Enum.GetValues(typeof(mytest))
.Cast<int>()
.Aggregate(0, (s, f) => s | f);
Or in a wrapper method
TEnum GetAll<TEnum>() where TEnum : struct
{
return (TEnum) (object)
Enum.GetValues(typeof(TEnum))
.Cast<int>()
.Aggregate(0, (s, f) => s | f);
}
full credit for this double-cast trick goes to @millimoose
The easiest way to ensure that all of the enum's bits are set it to just set all bits:
mytest allValues = (mytest)int.MaxValue;
This assumes that there's no problem setting bits that don't correspond to any enum, but that's likely true. You can AND this with any enum value and it will come out true, which is most likely the end goal.
It is not as easy as it looks at first sight given the underlying type cast issues:
static public TEnum GetAllFlags<TEnum>() where TEnum : struct, IComparable, IFormattable, IConvertible
{
unchecked
{
if (!typeof(TEnum).IsEnum)
throw new InvalidOperationException("Can't get flags from non Enum");
object val = null;
switch (Type.GetTypeCode(Enum.GetUnderlyingType(typeof(TEnum))))
{
case TypeCode.Byte:
case TypeCode.SByte:
val = Enum.GetValues(typeof(TEnum))
.Cast<Byte>()
.Aggregate(default(Byte), ( s, f) => (byte)(s | f));
break;
case TypeCode.Int16:
case TypeCode.UInt16:
val = Enum.GetValues(typeof(TEnum))
.Cast<UInt16>()
.Aggregate(default(UInt16), ( s, f) => (UInt16)(s | f));
break;
case TypeCode.Int32:
case TypeCode.UInt32:
val = Enum.GetValues(typeof(TEnum))
.Cast<UInt32>()
.Aggregate(default(UInt32), ( s, f) => (UInt32)(s | f));
break;
case TypeCode.Int64:
case TypeCode.UInt64:
val = Enum.GetValues(typeof(TEnum))
.Cast<UInt64>()
.Aggregate(default(UInt64), ( s, f) => (UInt64)(s | f));
break;
default :
throw new InvalidOperationException("unhandled enum underlying type");
}
return (TEnum)Enum.ToObject(typeof(TEnum), val);
}
}
More about this kind of conversions can be found here
Use Enumerable.Aggregate() to bitwise-or them together. This will work even if you have enum values that represent multiple set bits, as opposed to Sum()
.
var myTestValues = (MyTest[]) typeof(MyTest).GetEnumValues();
var sum = myTestValues.Aggregate((a, b) => a | b);
sum.Dump();
It's a little tricky to make this generic because you can't constrain generic types to be enums, nor do the primitive types have any subtype relationship to one another. The best I could come up with assumes that the underlying type is int
which should be good enough most of the time:
TEnum AllEnums<TEnum>()
{
var values = typeof(TEnum).GetEnumValues().Cast<int>();
return (TEnum) (object) values.Aggregate((a,b) => a|b);
}
How about something like
var all = Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>().Last() * 2 - 1;
basically
all = max*2-1
this only works if all values are present from 1 to the max value.
1,2,4...32,64...