Не проверено, используйте на свой страх и риск, но должны решить проблему достаточно обобщенно. System.Enum
не является допустимым ограничением, поскольку технически C # разрешает наследование только в / с class
, бэкэнд обходит это для Enum
и ValueType
. Так что извините за уродливый кастинг. Это также не очень эффективно, но если вы не запускаете это для динамически сгенерированного типа, это нужно делать только один раз за выполнение (или один раз за период, если сохранено).
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;
}
Это работает, собирая все значения и ИЛИ их вместе, а не суммируя, если есть составные числа. Затем оно берет каждое целое число до максимума и маскирует их обратным значением каждого флага, в результате чего действительные биты становятся равными 0, что позволяет нам идентифицировать те биты, которые невозможны.
Проверка в конце предназначена для отсутствия нуля в Enum. Вы можете удалить его, если у вас все нормально, всегда включая в результаты нулевое перечисление.
Дает ожидаемый результат 15, если ему дано перечисление, содержащее 2,4,6,32,34,16384.