检查枚举是否包含多个标志

Check if an enum contains more than one flag

我正在尝试检查 "enum instance" 是否包含多个标志。

[Flags]
public enum Foo 
{
  Bar = 1,
  Far = 2
}
var multiState = Foo.Bar | Foo.Far;

MoreThanOneFlag(multiState); // True

var singleState = Foo.Bar;

MoreThanOneFlag(singleState); // False

此外,我真的不想使用类似下面的东西:

var state = Foo.Bar | Foo.Far;

Console.WriteLine(state.ToString().Count(x => x == ',') > 0); // True

注意,我不关心 "instance" 包含哪些标志,我只想知道是否有多个标志。

您可以对 enum 值使用二进制对数函数,然后检查结果是否为整数。

下面的例子定义了扩展方法助手,returns true 当设置了多个标志时:

HelperExtenxsions.cs

public static class HelperExtenxsions
{
  public static bool HasMultipleFlags(this IConvertible enumValue) 
  {
    return Math.Log(enumValue.ToInt32(CultureInfo.InvariantCulture.NumberFormat), 2) % 1 != 0;
  }
}

Foo.cs

[Flags]
public enum Foo 
{
  Bar = 1,
  Far = 2
}

Program.cs

public static void Main()
{ 
  var enumValue = Foo.Bar | Foo.Far; 
  Console.WriteLine(enumValue.HasMultipleFlags()); // Prints 'True'

  enumValue = Foo.Bar;
  Console.WriteLine(enumValue.HasMultipleFlags()); // Prints 'False'
}

您可以在 conjunctionEnum.HasFlag(Enum) 中使用 Enum.GetValues 来迭代每个 constant 并确定是否位字段在当前实例中设置,return 它的计数。

[Flags]
public enum Foo
{
  One = 1,
  Two = 2,
  Four = 4,
  Eight = 8
}

var state1 = Foo.One;
var state2 = Foo.Two;//
var state3 = Foo.One | Foo.Two; 
var state4 = Foo.Two | Foo.Four;

Console.WriteLine(MoreThanOneFlag(state1));//false
Console.WriteLine(MoreThanOneFlag(state2));//false
Console.WriteLine(MoreThanOneFlag(state3));//true
Console.WriteLine(MoreThanOneFlag(state4));// true
private static bool MoreThanOneFlag<TEnum>(TEnum state) where TEnum : Enum
{
  var names = Enum.GetValues(typeof(TEnum));
  var Flagcounter = names.OfType<TEnum>().Where(x=>state.HasFlag((TEnum)x)).Count();
  return Flagcounter > 1 ? true : false;
}

注意: 虽然如果您的应用程序需要性能,Enum.HasFlags 可能不是合适的解决方案,但 reliable, clean, and makes the code very obvious and expressive

参考:

I am trying to check if an "enum instance" contains more than one flag. I do not care which Flags the "instance" contains, I just want to know if there are more than one

Additionally I really don't wanna use something like the following:

 var state = Foo.Bar | Foo.Far;
 Console.WriteLine(state.ToString().Count(x => x == ',') > 0); // True

有很多不同的方法可以完成你想要的,我建议做一点(按位)检查:

 public static bool MoreThanOneFlag<TValue>(TValue flag) where TValue : Enum => (Convert.ToInt32(flag) & (Convert.ToInt32(flag) - 1)) != 0;

在上面的代码块中,我们通过使用 flag & (flag-1)) != 0(& 运算符)检查 flag 是否不是二的幂 其操作数的按位逻辑与。如果只设置了一个标志,那么我们假设该值将是 2 的幂,否则它不是 2 的幂。

或者,如果您不需要辅助函数,只需在任何地方执行该检查即可:

 bool value = (multiState & (multiState -1)) != 0;

有关按位的更多信息,please check out 此处有更多信息。

参考文献:

Bitwise and shift operators (C# reference)