枚举 - 所有选项值

时间:2011-12-13 11:19:47

标签: c# enums bit-manipulation flags

有没有办法在枚举中添加“所有值”选项而不必在每次将新值添加到枚举时更改其值?

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

更新

结束从long继承并使用long.MaxValue for All选项。

8 个答案:

答案 0 :(得分:34)

由于您应该在标志枚举中定义空值,例如None = 0,定义All值的最简单方法是简单地反转None中的所有位。

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

请注意,~0而不是~None对于无符号的支持类型不起作用,因为它是-1,这对于无符号

来说不是有效值

编辑:答案被修改为使用反转的None而不是显式常量,例如0x7FFFFFFF或~0,因为这也适用于无符号

答案 1 :(得分:12)

应该是这样的:

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

答案 2 :(得分:4)

枚举可以由许多不同长度的整数类型(short,int,long)组成。这使得#FFFFFFFF解决方案不合适(正如@MarcGravell评论中指出的那样)。

枚举可以由无符号类型组成(uint用于isntance)。这使得-1解决方案不合适。

我最好的选择是,免维护:

All = ~0

答案 3 :(得分:3)

想法是使用枚举的行为来计算最后一个值。

在所有“真实”枚举值之后添加 Last 字段。

所有字段等于(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,
}

我在How to use Enum with aditional options (All, None)

回答了这个问题

您可以在Enum Trick查看我的博客,了解更多信息和想法。

答案 4 :(得分:2)

不,没有内置任何内容可以使这样的All选项在枚举更改时自动更新。

您可能希望有一个特殊值(监视器值),这意味着All(比如-1),即使它不是所有选项的按位总和。

另一种方法是使用一个已打开所有位的值:

All = 0xFFFFFFFF

答案 5 :(得分:0)

你可以使用一个小技巧

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

如果添加了值为0(None = 0,)的“无”枚举名称,则需要在长度后加上“-1”。

答案 6 :(得分:0)

如果您使用单独类型的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,因此只能以线程安全的方式执行一次计算。

正如我在代码注释中写的那样,很遗憾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;
    }

哦,好吧:(

答案 7 :(得分:0)

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;
  }
相关问题