Enums - значение всех опций
Есть ли способ добавить параметр "Все значения" в перечисление без необходимости изменять его значение каждый раз, когда новое значение добавляется в перечисление?
[Flags]
public enum SomeEnum
{
SomeValue = 1,
SomeValue2 = 1 << 1,
SomeValue3 = 1 << 2,
SomeValue4 = 1 << 3,
All = ?
}
Update:
Закончено наследование от long и использование опции long.MaxValue
для всех.
Ответы
Ответ 1
Поскольку вы должны определить пустое значение в перечислении флагов, например None = 0
, самым простым способом определения значения All
является просто инвертирование всех битов в None
.
[Flags]
enum MyEnum
{
None = 0,
A = 1
B = 2,
C = 4,
...
All = ~None
}
Обратите внимание, что ~0
вместо ~None
не будет работать для неподписанных типов поддержки, так как это -1, что не является допустимым значением для unsigned
Изменить: ответ был изменен, чтобы использовать инвертированный None вместо явной константы, такой как 0x7FFFFFFF или ~ 0, так как это работает и для unsigned
Ответ 2
Это должно быть так:
[Flags]
public enum SomeEnum
{
SomeValue = 1,
SomeValue2 = 1 << 1,
SomeValue3 = 1 << 2,
SomeValue4 = 1 << 3,
All = SomeValue | SomeValue2 | SomeValue3 | SomeValue4
}
Ответ 3
Перечисление может быть сделано из множества различных целых чисел длины (short, int, long). Это делает решение #FFFFFFFF
неуместным (как указано в комментарии @MarcGravell).
Перечисление может быть выполнено из неподписанных типов (uint для isntance). Это делает решение -1
неуместным.
Мой лучший выбор - без обслуживания:
All = ~0
Ответ 4
Идея заключается в использовании поведения перечисления для вычисления последнего значения.
Добавить последнее поле после всех "реальных" значений перечисления.
Добавить все поле равно (Last << 1) - 3
.
[Flags]
public enum SomeEnum
{
SomeValue = 1,
SomeValue2 = 1 << 1,
SomeValue3 = 1 << 2,
SomeValue4 = 1 << 3,
// Do not add values after this
Last,
All = (Last << 1) - 3,
}
Я ответил на это: Как использовать Enum с дополнительными параметрами (Все, Нет)
Вы можете проверить мой блог на Enum Trick для получения дополнительной информации и идей.
Ответ 5
Нет, ничего не построено, так как при изменении Enum автоматически будет обновляться такая опция All
.
Возможно, вам понадобится специальное значение (значение монитора), которое означает All
(скажем, -1), даже если это не поразрядная сумма всех параметров.
Альтернативой является использование значения, в котором все биты включены:
All = 0xFFFFFFFF
Ответ 6
Вы можете использовать небольшой трюк
(SomeEnum)( (1 << ( Enum.GetValues( typeof(SomeEnum) ).Length ) ) -1 )
Если вы добавили имя "Нет" Enum со значением = 0 (None = 0,
), вам нужно поставить "-1" после Length.
Ответ 7
Это возможно, если вы в порядке с полем static readonly
в отдельном типе, а не как поле перечисления const
:
[Flags]
public enum SomeEnum
{
None = 0,
SomeValue = 1,
SomeValue2 = 1 << 1,
SomeValue3 = 1 << 2,
SomeValue4 = 1 << 3,
}
public static class SomeEnumUtility {
private static readonly SomeEnum[] _someEnumValues = (SomeEnum[])Enum.GetValues( typeof(SomeEnum) );
public static readonly SomeEnum SomeEnum_All = GetSomeEnumAll();
// Unfortunately C# does not support "enum generics" otherwise this could be a generic method for any Enum type
private static SomeEnum GetSomeEnumAll() {
SomeEnum value = SomeEnum.None; // or `(SomeEnum)0;` if None is undefined.
foreach(SomeEnum option in _someEnumValues) {
value |= option;
}
return value;
}
}
Тогда вы можете получить SomeEnumUtility.SomeEnum_All
. Поскольку это static readonly
, вычисление выполняется только один раз, поточно-безопасным способом.
Как я писал в комментарии к коду, он досадно, что С# не поддерживает generic generics, иначе вы могли бы сделать это:
private static TEnum GetEnumAllFlags<TEnum>() where TEnum : enum {
TEnum[] allValues = Enum.GetValues<TEnum>();
TEnum value = (TEnum)0;
foreach(TEnum option in allValues) {
value |= option;
}
return value;
}
Хорошо: (
Ответ 8
public static T EnumSetAll<T>() where T : struct, Enum
{
string str = string.Join(", ", Enum.GetNames(typeof(T)));
if (Enum.TryParse<T>(str, out var e))
return e;
return default;
}