Подтвердить что ты не робот

Enums - значение всех опций

Есть ли способ добавить параметр "Все значения" в перечисление без необходимости изменять его значение каждый раз, когда новое значение добавляется в перечисление?

[Flags] 
public enum SomeEnum
{
    SomeValue =  1,
    SomeValue2 = 1 << 1,
    SomeValue3 = 1 << 2,
    SomeValue4 = 1 << 3,
    All = ?
}

Update:

Закончено наследование от long и использование опции long.MaxValue для всех.

4b9b3361

Ответ 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;
  }