枚举-所有选项值

本文关键字:选项 -所 枚举 | 更新日期: 2023-09-27 18:17:35

是否有一种方法来添加一个"所有值"选项的枚举,而不必改变其值每次一个新的值被添加到枚举?

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

最终继承了long并使用long.MaxValue for All选项

枚举-所有选项值

既然你应该定义一个空值Flags enum such as None = 0 , the simplest way of defining the All value is by simply inverting all the bits in None ' .

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

请注意,~0而不是~None将不能用于无符号的备份类型,因为它是-1,这不是无符号的有效值。

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

应该是这样的:

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

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

enum可以由unsigned类型组成(例如:int)。这使得-1解决方案不合适。

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

All = ~0

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

在所有'real'枚举值之后添加最后一个字段。

添加所有字段等于(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与其他选项(All, None)

你可以在Enum Trick查看我的博客获取更多信息和想法

不,当枚举改变时,没有任何构建会使这样的All选项自动更新。

您可能希望有一个特殊的值(监视器值)来表示All(例如-1),即使它不是所有选项的按位和。

另一种选择是使用一个所有位都打开的值:

All = 0xFFFFFFFF

你可以使用一个小技巧

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

如果您添加了一个value = 0 (None = 0,)的'None' Enum名称,那么您需要在Length后面加上一个'-1'。

如果您同意将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#不支持枚举泛型,否则你可以这样做:

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

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