简体   繁体   English

有没有其他方法来测试枚举位字段?

[英]Is there another way to test Enum bit fields?

When using Enums with bit fields: 将Enums与位字段一起使用时:

   enum  ReallyBigEnum  { FirstChoice = 0x01, AnotherOption = 0x02 }
   ReallyBigEnum  flag = ReallyBigEnum.FirstChoice | ReallyBigEnum.AnotherOption;

the code used to test the bits is: 用于测试位的代码是:

   if( (flag & ReallyBigEnum.AnotherOption) == ReallyBigEnum.AnotherOption ) { ... }

which seems verbose and error prone because of the need to repeat the bit being tested. 由于需要重复被测试的位,这看起来很冗长且容易出错。

It would be nice if there were some way to say: 如果有某种方式可以说:

   if( flag.IsSet( ReallyBigEnum.AnotherOption ) ) { ... }

but Enums don't support instance methods. 但是Enums不支持实例方法。 So, I tried a template function: 所以,我尝试了一个模板功能:

   class Enums
   {
      public static bool IsSet<T>( T flag, T bit ) { return (flag & bit) == bit; }
   }

but the code to test bits then looks like this: 但是测试位的代码看起来像这样:

   if( Enums.IsSet<ReallyBigEnum>( flag, ReallyBigEnum.AnotherOption ) ) { ... }

which is a lot to write. 写的很多。 Then I tried to shorten it: 然后我试着缩短它:

   class Enums
   {
      public static bool IsSet( int flag, int bit ) { return (flag & bit) == bit; }
   }

but then you have to cast each value to its base type like this: 但是你必须将每个值转换为它的基类型,如下所示:

   if( Enums.IsSet( (int)flag, (int)ReallyBigEnum.AnotherOption ) ) { ... }

which is also a pain to code and loses the benefit of type checking. 这也是代码的痛苦并且失去了类型检查的好处。

The same function could be written to use 'object' parameters, but then the object type and underlying base type would have to be tested. 可以编写相同的函数来使用'object'参数,但是必须测试对象类型和底层基类型。

So, I'm stuck with the standard, redundant way at the top. 所以,我坚持使用顶部的标准冗余方式。

Does anyone have other ideas on a clean, simple way of testing Enum bit fields? 有没有人对干净,简单的测试枚举位字段的方法有其他想法?

Much Thanks. 非常感谢。

Up to .Net 3.5 this is your only option. 高达.Net 3.5这是您唯一的选择。 In .Net 4.0 there is a HasFlag method on the enum. 在.Net 4.0中,枚举上有一个HasFlag方法。

if((flag & ReallyBigEnum.AnotherOption) != 0) { ... }

UPDATED: 更新:

The above obviously work only if you're testing a single bit. 只有当你测试一个位时,上面显然才有效。 If you want to test multiple bits, then something else is required, depending on whether you are checking for all bits or any bit. 如果要测试多个位,则需要其他内容,具体取决于您是检查所有位还是任何位。

Testing that any of a set of bits is set 测试是否设置了任何一组位

For this case, just use a variant of the single bit version. 对于这种情况,只需使用单比特版本的变体。

if((flag & (ReallyBigEnum.FirstOption | ReallyBigEnum.AnotherOption)) != 0) { ... }

Testing that all of a set of bits is set 测试是否设置了所有一组位

For this case to achive clarity and reliability, I suggest creating a constant that contains all of the bits. 为了达到清晰度和可靠性,我建议创建一个包含所有位的常量。

const int ReallyBigEnum WickedAwesomeOptions = ReallyBigEnum.FirstOption | ReallyBigEnum.AnotherOption;
...
if (flag & WickedAwesomeOptions == WickedAwesomeOptions) { ... }

Some of the redundancy is still there, but it is not fragile or confusing, and it is easy to maintain. 一些冗余仍然存在,但它不易碎或混乱,并且易于维护。

If the bit combination applies broadly, then you can add it to the enum itself. 如果位组合适用广泛,那么您可以将它添加到枚举本身。

[Flags]
enum ReallyBigEnum
{
    FirstOption = 1,
    AnotherOption = 2,
    WickedAwesomeOptions = FirstOption | AnotherOption,
}
....
if (flag & ReallyBigEnum.WickedAwesomeOptions == ReallyBigEnum.WickedAwesomeOptions) { ... }
/// <summary>
/// Taken from https://stackoverflow.com/questions/9033/hidden-features-of-c/407325#407325
/// instead of doing (enum & value) == value you can now use enum.Has(value)
/// </summary>
/// <typeparam name="T">Type of enum</typeparam>
/// <param name="type">The enum value you want to test</param>
/// <param name="value">Flag Enum Value you're looking for</param>
/// <returns>True if the type has value bit set</returns>
public static bool Has<T>(this System.Enum type, T value)
{
   return (((int)(object)type & (int)(object)value) == (int)(object)value);
} 

Here is an Extension Method I took from the above link 这是我从上面的链接中获取的扩展方法

Use: 使用:

MyFlagEnum e = MyFlagEnum.First | MyFlagEnum.Second;
if(e.Has(MyFlagEnum.First))
{
   // Do stuff
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM