C#:检查一组枚举值的最佳方法是什么?

假设你有enum MyEnum {A = 0, B = 1, C = 2, D = 4, E = 8, F = 16};

在某些时候,您有一个函数将检查MyEnum的实例,如果它是C,D或F则返回true

 bool IsCDF(MyEnum enumValue) { return //something slick } 

我记得有一些非常灵巧的方法可以进行位移和预先形成这种操作,比一堆三元if语句读取方式更好但是对于我的生活我不记得它是什么。

谁知道?

如果将其设为[Flags]枚举,则可以为每个枚举值分配不同的位值(1,2,4,8,1 …)。 然后,您可以使用按位运算来确定值是否是一组可能值之一。

所以,看看它是C,D还是F:

 bool IsCDF(MyEnum enumValue) { return ((enumValue & (MyEnum.C | MyEnum.D | MyEnum.F)) != 0); } 

或使用HasFlag() (效率较低但更易读):

 bool IsCDF(MyEnum enumValue) { return enumValue.HasFlag(MyEnum.C | MyEnum.D | MyEnum.F); } 

请注意,这不适用于值0(在您的示例中为“A”),并且必须注意所有枚举值都会解析为唯一位值(即非零幂的2)。

这种方法的优点是:

  • 它通常需要执行单个CPU指令/周期,而执行三个单独的“if”检查将需要3个或更多指令(取决于您的目标平台)。
  • 您可以将要测试的值集作为枚举值(单个整数)传递,而不是需要使用枚举值列表。
  • 您可以使用按位运算执行许多其他有用的操作,使用普通的数值/比较方法会很笨拙和缓慢。

方便提示:在定义[Flags]枚举时,使用左移( << )使位值更清晰(更难以出错),尤其是对于高阶位:

 [Flags] enum MyEnum { A = 1 << 0, // Equivalent to 1 B = 1 << 1, // Equivalent to 2 C = 1 << 2, // Equivalent to 4 D = 1 << 3, // Equivalent to 8 … Big = 1 << 26, // Equivalent to 67108864 } 
 bool IsCDF(MyEnum enumValue) { return new[]{MyEnum.C, MyEnum.D, MyEnum.F}.Contains(enumValue); } 

我可能会使用Unconstrained Melody来保持整洁:

 if (value.HasAny(MyEnum.C | MyEnum.D | MyEnum.E)) { ... } 

我可能会将“C,D或E”位提取到命名常量中 – 可能在枚举本身中,如果它有意义:

可能是你在考虑FlagsAttribute 。 请看这里和这里的一些例子。

您可以使用Enum.HasFlag方法

也许这个扩展类对你有用:

 public static class Flags { ///  /// Checks if the type has any flag of value. ///  ///  ///  ///  ///  public static bool HasAny(this System.Enum type, T value) { try { return (((int) (object) type & (int) (object) value) != 0); } catch { return false; } } ///  /// Checks if the value contains the provided type. ///  ///  ///  ///  ///  public static bool Has(this System.Enum type, T value) { try { return (((int)(object)type & (int)(object)value) == (int)(object)value); } catch { return false; } } ///  /// Checks if the value is only the provided type. ///  ///  ///  ///  ///  public static bool Is(this System.Enum type, T value) { try { return (int)(object)type == (int)(object)value; } catch { return false; } } ///  /// Appends a value. ///  ///  ///  ///  ///  public static T Add(this System.Enum type, T value) { try { return (T)(object)(((int)(object)type | (int)(object)value)); } catch (Exception ex) { throw new ArgumentException( string.Format( "Could not append value from enumerated type '{0}'.", typeof(T).Name ), ex); } } ///  /// Appends a value. ///  ///  ///  ///  ///  public static void AddTo(this System.Enum type, ref T value) { try { value = (T)(object)(((int)(object)type | (int)(object)value)); } catch (Exception ex) { throw new ArgumentException( string.Format( "Could not append value from enumerated type '{0}'.", typeof(T).Name ), ex); } } ///  /// Removes the value. ///  ///  ///  ///  ///  public static T Remove(this System.Enum type, T value) { try { return (T)(object)(((int)(object)type & ~(int)(object)value)); } catch (Exception ex) { throw new ArgumentException( string.Format( "Could not remove value from enumerated type '{0}'.", typeof(T).Name ), ex); } } ///  /// Removes the value. ///  ///  ///  ///  ///  public static void RemoveFrom(this System.Enum type, ref T value) { try { value = (T)(object)(((int)(object)type & ~(int)(object)value)); } catch (Exception ex) { throw new ArgumentException( string.Format( "Could not remove value from enumerated type '{0}'.", typeof(T).Name ), ex); } } } 
 return (enumValue & MyEnum.C == MyEnum.C) || (enumValue & MyEnum.D == MyEnum.D) || (enumValue & MyEnum.F == MyEnum.F);