【问题标题】:Best way to get all bits of an enum flag?获取枚举标志的所有位的最佳方法?
【发布时间】:2010-08-11 21:37:12
【问题描述】:

我有一个带有标志属性的枚举。

我的问题是,我想获得所有选项的整数位掩码,而无需自己手动组合所有位。 我想这样做以与其他一些 int 字段进行比较,并且我想保护以防未来的开发人员向枚举广告更多位选项。

另一件事是我的枚举标志中的位将全部手动分配,所以我不能简单地获取下一个值并减去 1。

【问题讨论】:

    标签: c# enums


    【解决方案1】:

    如果我理解你的要求正确,这应该对你有用:

    Enum.GetValues(typeof(Enum)).Cast<int>().Sum();
    

    然后您可以将其转换回您的typeof(Enum)

    [Flags]
    public enum Values
    {
        Value_1 = 1,
        Value_2 = 2,
        Value_3 = 4,
        Value_4 = 8,
        Value_5 = 16,
        Value_6 = 32,
        Value_7 = 64,
        Value_8 = 128,
        Value_9 = 256
    }
    
    static void Main(string[] args)
    {
        Values values = (Values)Enum.GetValues(typeof(Values)).Cast<int>().Sum();
    }
    

    【讨论】:

    • 只有在定义的类型中没有重复时才有效,这通常发生在同义词或预先组合的常见组合中。
    • 这绝对是最干净的解决方案,您也可以只获取返回的 Array 并执行您想要的任何其他计算,例如 ORing 而不是求和。
    • 很好,但它仅在底层类型为 int 时才有效(否则转换失败)。我建议的解决方案更通用(但对于这种情况可能有点矫枉过正......)
    • @LukeH 我同意这些是经常创建的。但是 OP 不会询问当时所有枚举值的总和。他会知道其中存在带有组合标志的重复项,并希望提及某些值不应包含在总和中。这是我的想法。如果您只想添加某些值,则不需要添加所有值。
    • 我只是认为这些都是有效的问题,但不在 OP 提出的问题范围内。如果他提到了其中一些情况,我认为反对票和 cmets 会更相关。但他问了一个具体的问题,我提供了一个具体的答案。不认为我们需要让答案比问题更难。
    【解决方案2】:
    // uses a ulong to handle all possible underlying types without error
    var allFlags = Enum.GetValues(typeof(YourEnumType))
                       .Cast<YourEnumType>()
                       .Aggregate((YourEnumType)0, (a, x) => a | x, a => (ulong)a);
    

    【讨论】:

    • 我不能不 +1 这个,因为它与“添加答案”消息出现时我输入的内容非常接近。它确实在长枚举上失败,所以也许将 Cast 更改为 Cast?
    • @Jon:已修复。聚合值现在输入为ulong,以便它可以处理所有可能的基础类型。 (我将其转换为 YourEnumType 而不是保留它,因为 OP 要求提供 integer 位掩码。)
    【解决方案3】:

    看看我的 Unconstrained Melody 项目,它做了一些坏事,允许在受限于枚举和委托的泛型方法上构建好的功能。

    在这种情况下,我想你应该打电话给Flags.GetUsedBits&lt;YourEnumType&gt;()

    如果您不介意使用额外的(非常小的)库,我想 Unconstrained Melody 在处理标志时让生活更美好。如果您有任何功能要求,我很乐意看看 :)

    【讨论】:

    • 我会接受这个答案,除非有人自己想出一些东西。
    • @Winforms:哦,当然,您可以在自己的代码中完成我在 Unconstrained 中所做的一切 - 除了使用通用约束将类型参数约束为枚举(或委托)。那是邪恶的黑客位......
    【解决方案4】:

    有点粗鲁但像这样?

    [Flags]
    enum SomeFlags
    {
        Flag1 = 1,
        Flag2 = 2,
        Flag3 = 4,
        Flag4 = 16,
        Flag5 = 32,
        Flag6 = 64
    }
    
    static void Main(string[] args)
    {
        SomeFlags flags = 0;
    
        SomeFlags[] values = (SomeFlags[])Enum.GetValues(typeof(SomeFlags));
        Array.ForEach<SomeFlags>(values, delegate(SomeFlags v) { flags |= v; });
    
        int bitMask = Convert.ToInt32(flags);
    }
    

    【讨论】:

      【解决方案5】:

      这是一种方法,使用 Jon Skeet 和 Marc Gravell 编写的 generic operators 中的想法:

      void Main()
      {
          Console.WriteLine(CombineAllFlags<MyEnum>()); // Prints "Foo, Bar, Baz"
      }
      
      [Flags]
      public enum MyEnum
      {
          Foo = 1,
          Bar = 2,
          Baz = 4
      }
      
      public static TEnum CombineAllFlags<TEnum>()
      {
          TEnum[] values = (TEnum[])Enum.GetValues(typeof(TEnum));
          TEnum tmp = default(TEnum);
          foreach (TEnum v in values)
          {
              tmp = EnumHelper<TEnum>.Or(tmp, v);
          }
          return tmp;
      }
      
      static class EnumHelper<T>
      {
          private static Func<T, T, T> _orOperator = MakeOrOperator();
      
          private static Func<T, T, T> MakeOrOperator()
          {
              Type underlyingType = Enum.GetUnderlyingType(typeof(T));
              ParameterExpression xParam = Expression.Parameter(typeof(T), "x");
              ParameterExpression yParam = Expression.Parameter(typeof(T), "y");
              var expr =
                  Expression.Lambda<Func<T, T, T>>(
                      Expression.Convert(
                          Expression.Or(
                              Expression.Convert(xParam, underlyingType),
                              Expression.Convert(yParam, underlyingType)),
                          typeof(T)),
                      xParam,
                      yParam);
              return expr.Compile();
          }
      
          public static T Or(T x, T y)
          {
              return _orOperator(x, y);
          }   
      }
      

      此代码动态创建一个将枚举值与 OR 运算符组合的委托

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-10-21
        • 1970-01-01
        • 1970-01-01
        • 2011-08-13
        相关资源
        最近更新 更多