[Flags]
public enum MyEnum
{
None = 0,
Setting1 = (1 << 1),
Setting2 = (1 << 2),
Setting3 = (1 << 3),
Setting4 = (1 << 4),
}
I need to be able to somehow loop over every posible setting and pass the settings combination to a function. Sadly I have been unable to figure out how to do this
Use a list comprehension to get a list of all enum values, e.g. values = [member. value for member in Sizes] . On each iteration, access the value attribute on the enum member to get a list of all of the enum's values.
A Flags is an attribute that allows us to represent an enum as a collection of values rather than a single value. So, let's see how we can implement the Flags attribute on enumeration: [Flags] public enum UserType. {
Using enums can make it easier to document intent, or create a set of distinct cases. TypeScript provides both numeric and string-based enums.
Not tested, use at your own risk, but should solve the problem generically enough. System.Enum
is not a valid restriction as technically C# only allow inheritance in/with class
the backend bypasses this for Enum
and ValueType
. So sorry for the ugly casting. It is also not horribly efficient but unless you are running this against a dynamically generated type it should only ever have to be done once per execution (or once period if saved).
public static List<T> GetAllEnums<T>()
where T : struct
// With C# 7.3 where T : Enum works
{
// Unneeded if you add T : Enum
if (typeof(T).BaseType != typeof(Enum)) throw new ArgumentException("T must be an Enum type");
// The return type of Enum.GetValues is Array but it is effectively int[] per docs
// This bit converts to int[]
var values = Enum.GetValues(typeof(T)).Cast<int>().ToArray();
if (!typeof(T).GetCustomAttributes(typeof(FlagsAttribute), false).Any())
{
// We don't have flags so just return the result of GetValues
return values;
}
var valuesInverted = values.Select(v => ~v).ToArray();
int max = 0;
for (int i = 0; i < values.Length; i++)
{
max |= values[i];
}
var result = new List<T>();
for (int i = 0; i <= max; i++)
{
int unaccountedBits = i;
for (int j = 0; j < valuesInverted.Length; j++)
{
// This step removes each flag that is set in one of the Enums thus ensuring that an Enum with missing bits won't be passed an int that has those bits set
unaccountedBits &= valuesInverted[j];
if (unaccountedBits == 0)
{
result.Add((T)(object)i);
break;
}
}
}
//Check for zero
try
{
if (string.IsNullOrEmpty(Enum.GetName(typeof(T), (T)(object)0)))
{
result.Remove((T)(object)0);
}
}
catch
{
result.Remove((T)(object)0);
}
return result;
}
This works by getting all the values and ORing them together, rather than summing, in case there are composite numbers included. Then it takes every integer up to the maximum and masking them with the reverse of each Flag, this causes valid bits to become 0, allowing us to identify those bits that are impossible.
The check at the end is for missing zero from an Enum. You can remove it if you are fine with always including a zero enum in the results.
Gave the expected result of 15 when given an enum containing 2,4,6,32,34,16384.
Since it's a flagged enum, why not simply:
An example would look like this
var highestEnum = Enum.GetValues(typeof(MyEnum)).Cast<int>().Max();
var upperBound = highestEnum * 2;
for (int i = 0; i < upperBound; i++)
{
Console.WriteLine(((MyEnum)i).ToString());
}
Here is a solution particular to your code sample, using a simple for loop (don't use, see update below)
int max = (int)(MyEnum.Setting1 | MyEnum.Setting2 | MyEnum.Setting3 | MyEnum.Setting4);
for (int i = 0; i <= max; i++)
{
var value = (MyEnum)i;
SomeOtherFunction(value);
}
Update: Here is a generic method that will return all possible combinations. And thank @David Yaw for the idea to use a queue to build up every combination.
IEnumerable<T> AllCombinations<T>() where T : struct
{
// Constuct a function for OR-ing together two enums
Type type = typeof(T);
var param1 = Expression.Parameter(type);
var param2 = Expression.Parameter(type);
var orFunction = Expression.Lambda<Func<T, T, T>>(
Expression.Convert(
Expression.Or(
Expression.Convert(param1, type.GetEnumUnderlyingType()),
Expression.Convert(param2, type.GetEnumUnderlyingType())),
type), param1, param2).Compile();
var initalValues = (T[])Enum.GetValues(type);
var discoveredCombinations = new HashSet<T>(initalValues);
var queue = new Queue<T>(initalValues);
// Try OR-ing every inital value to each value in the queue
while (queue.Count > 0)
{
T a = queue.Dequeue();
foreach (T b in initalValues)
{
T combo = orFunction(a, b);
if (discoveredCombinations.Add(combo))
queue.Enqueue(combo);
}
}
return discoveredCombinations;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With