检查一个枚举类型是否包含多个标志。

5
我正在尝试检查“枚举实例”是否包含多个标志。
[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"包含哪些标志,我只想知道是否存在多个实例。


1
有很多重复的问题,比如这个。你可以使用&运算符或HasFlag方法。 - Pavel Anikhouski
5
执行一个位运算... bool value = (multiState & (multiState -1)) != 0; 注:该段代码用于判断变量 multiState 的二进制表示中是否有多个比特位同时被设置为1。如果是,则返回 true,否则返回 false。 - Trevor
2
这个回答解决了你的问题吗?如何计算枚举中设置的标志数 - Pavel Anikhouski
1
也许他们想检查非法组合。 - Chronicle
3
这应该是答案,而不是评论。 - Alsein
显示剩余8条评论
3个回答

4

我正在尝试检查"枚举实例"是否包含多个标记。

我不关心"实例"包含哪些标记,只想知道是否有多个标记。

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

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

实现您想要的有很多种不同方法,我建议使用位(bitwise)检查:

 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的幂次方,否则它就不是2的幂次方。

或者,如果您不想要一个辅助函数,可以在任何地方执行该检查:

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

关于按位运算的更多信息,请在此处查看更多信息。

参考文献:

按位与移位运算符 (C# 参考)


1
我喜欢它!虽然不需要使用Convert.ToInt32,但只需强制转换为int即可工作正常。如果您要非常完整,必须检查积分类型并将其用于值。不过这超出了范围。 :-) - Jamie

2

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

下面的示例定义了一个扩展方法帮助程序,当设置了多个标志时返回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'
}

2
枚举是现代 C# 中有效的约束条件,可以使用 TEnum : Enum。 - Chronicle
1
是的,正确。但我认为你不能仅仅使用强制转换将“Enum”转换为整数值。 - BionicCode

0
你可以使用 Enum.GetValuesEnum.HasFlag(Enum) 结合起来,遍历每个 常量 并确定当前实例中是否设置了位字段,并返回其计数。
[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 可能不是合适的解决方案,但它更加可靠、清晰和使代码非常明显和表达

参考:

C# Enum.HasFlag vs. Bitwise AND Operator Check


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接