在标志上使用按位运算符

Mal*_*ist 26 .net c# bit-manipulation bit-fields

我有四面旗帜

Current = 0x1  
Past = 0x2  
Future = 0x4  
All = 0x7
Run Code Online (Sandbox Code Playgroud)

假设我收到了两个标志Past和Future(setFlags(PAST | FUTURE)).我怎么知道它Past是否在里面?同样,我怎么能告诉它Current不在其中?这样我就不必测试每种可能的组合.

Mar*_*ell 43

如果您希望测试掩码中的所有位匹配:

if((value & mask) == mask) {...}
Run Code Online (Sandbox Code Playgroud)

如果您希望测试掩码中的任何一个位匹配:

if((value & mask) != 0) {...}
Run Code Online (Sandbox Code Playgroud)

当您测试多个事物的值时,差异最明显.

要测试排除:

if ((value & mask) == 0) { }
Run Code Online (Sandbox Code Playgroud)


Vil*_*lx- 29

首先 - 使用带有FlagAttribute的枚举.这就是它的用途.

[Flags]
public enum Time
{
    None = 0
    Current = 1,
    Past = 2,
    Future = 4
    All = 7
}
Run Code Online (Sandbox Code Playgroud)

然后测试就像这样:

if ( (x & Time.Past) != 0 )
Run Code Online (Sandbox Code Playgroud)

或这个:

if ( (x & Time.Past) == Time.Past )
Run Code Online (Sandbox Code Playgroud)

如果"过去"是旗帜的组合并且您想要测试它们,后者将更好地工作.

设置是这样的:

x |= Time.Past;
Run Code Online (Sandbox Code Playgroud)

取消设置是这样的:

x &= ~Time.Past;
Run Code Online (Sandbox Code Playgroud)

  • @Roylee - 没错!:) 请注意,“无”和“全部”有点不同——它们本身不是标志,而是标志的组合。我也可以让 `PastOrPresent=3` 因为 `1 & 2 = 3`。只有将这些添加到经常一起使用的组合才有意义。它可以节省打字并避免错误。 (2认同)
  • @Roylee-噢,地狱。我打错了 应该是`1 | 2 = 3`。:) (2认同)

Bri*_*sen 12

您可能还需要添加一个扩展方法是这样

  enum states {
     Current = 0x1,
     Past = 0x2,
     Future = 0x4,
     All = 0x7
  };

  static bool Is(this states current, states value) {
     return (current & value) == value;
  }
Run Code Online (Sandbox Code Playgroud)

然后你可以这样做:

 if(state.Is(states.Past)) {
    // Past
 }
Run Code Online (Sandbox Code Playgroud)


Kod*_*ody 6

Marc Gravell 和 Vilx- 的答案的附录:

您标记的枚举不应指定“全部”的金额,它应仅包含您现有的值。这适用于任何计算值。

[Flags]
public enum Time
{
    None = 0,
    Current = 1,
    Past = 2,
    Future = 4,
    All = Current | Past | Future
}
Run Code Online (Sandbox Code Playgroud)

请注意,Vilx- 删除了对值使用十六进制。这很重要,因为一旦超过 0x8,您的值将必须符合十六进制。你应该只保留十进制。

编辑: 我还想补充一点,您可以使用位移位而不是十六进制/十进制。

这看起来像:

[Flags]
public enum Time
{
    None = 0,
    Current = 1,
    Past = 1 << 1, // 2, 10 binary
    Future = 1 << 2, // 4, 100 binary
 // Example = 1 << 3, // 8, 1000 binary
 // Example = 1 << 4, // 16, 10000 binary
    All = Current | Past | Future
}
Run Code Online (Sandbox Code Playgroud)


Ogg*_*las 5

如果您使用 .NET 4 或更高版本,我更喜欢这样做,更干净的 imao:

[Flags]
public enum Time
{
    None = 0
    Current = 1,
    Past = 2,
    Future = 4
}

myProp = Time.Past | Time.Future;

if (myProp.HasFlag(Time.Past))
{
    // Past is set...
}
Run Code Online (Sandbox Code Playgroud)