Enums - все значения параметров - PullRequest
23 голосов
/ 13 декабря 2011

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

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

Обновление:

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

Ответы [ 7 ]

34 голосов
/ 13 декабря 2011

Поскольку вы должны определить пустое значение в перечислении флагов, например None = 0, самый простой способ определить значение All - просто инвертировать все биты в None.

[Flags]
enum MyEnum
{
   None = 0,
   A = 1
   B = 2,
   C = 4,
   ...
   All = ~None
}

Обратите внимание, что ~0 вместо ~None не будет работать для неподписанных типов поддержки, поскольку это -1, что не является допустимым значением для неподписанных

Редактировать: Ответ был изменен для использования инвертированного Нетвместо явной константы, такой как 0x7FFFFFFF или ~ 0, поскольку это работает и для беззнаковых

12 голосов
/ 13 декабря 2011

Должно быть так:

[Flags] 
public enum SomeEnum
{
    SomeValue =  1,
    SomeValue2 = 1 << 1,
    SomeValue3 = 1 << 2,
    SomeValue4 = 1 << 3,
    All = SomeValue | SomeValue2 | SomeValue3 | SomeValue4
}
4 голосов
/ 16 июля 2014

Перечисление может состоять из множества целочисленных типов различной длины (short, int, long). Это делает решение #FFFFFFFF неуместным (как указано в комментарии @MarcGravell).

Перечисление может быть сделано из беззнаковых типов (uint для isntance). Это делает решение -1 неуместным.

Моя лучшая ставка - без обслуживания:

All = ~0
3 голосов
/ 16 января 2013

Идея состоит в том, чтобы использовать поведение перечисления для вычисления последнего значения.

Добавить Последнее поле после всех «реальных» значений перечисления.

Добавить Все поле равно (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 для получения дополнительной информации и идей.

2 голосов
/ 13 декабря 2011

Нет, ничего не построено, так как такая опция All автоматически обновляется при изменении Enum.

Возможно, вы захотите иметь специальное значение (значение монитора), которое означает All (скажем -1), даже если она не является побитовой суммой всех опций.

Альтернативой является использование значения, для которого включены все биты:

All = 0xFFFFFFFF
0 голосов
/ 31 декабря 2016

Это возможно, если у вас все в порядке с полем static readonly в отдельном типе, а не с полем const enum:

[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, вычисления выполняются только один раз в поточно-ориентированном режиме.

Как я уже писал в комментарии к коду, к сожалению, C # не поддерживает обобщенные типы enum, в противном случае вы можете сделать это:

    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;
    }

Ну да ладно: (

0 голосов
/ 11 июня 2013

Вы можете использовать маленький трюк

(SomeEnum)( (1 << ( Enum.GetValues( typeof(SomeEnum) ).Length ) ) -1 )

Если вы добавили имя Enum со значением «0» со значением = 0 (None = 0,), то вам нужно поставить «-1» после длины.

...