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