在我的生活中,我不记得如何设置,删除,切换或测试位域中的位。要么我不确定,要么我把它们弄混了,因为我很少需要它们。所以有一个“bit-cheat-sheet”会很好。

例如:

flags = flags | FlagsEnum.Bit4;  // Set bit 4.

or

if ((flags & FlagsEnum.Bit4)) == FlagsEnum.Bit4) // Is there a less verbose way?

你能给出所有其他常见操作的例子吗,最好是在c#语法中使用[Flags]枚举?


当前回答

@Drew

注意,除了在最简单的情况下,Enum。与手动编写代码相比,HasFlag会带来严重的性能损失。考虑下面的代码:

[Flags]
public enum TestFlags
{
    One = 1,
    Two = 2,
    Three = 4,
    Four = 8,
    Five = 16,
    Six = 32,
    Seven = 64,
    Eight = 128,
    Nine = 256,
    Ten = 512
}


class Program
{
    static void Main(string[] args)
    {
        TestFlags f = TestFlags.Five; /* or any other enum */
        bool result = false;

        Stopwatch s = Stopwatch.StartNew();
        for (int i = 0; i < 10000000; i++)
        {
            result |= f.HasFlag(TestFlags.Three);
        }
        s.Stop();
        Console.WriteLine(s.ElapsedMilliseconds); // *4793 ms*

        s.Restart();
        for (int i = 0; i < 10000000; i++)
        {
            result |= (f & TestFlags.Three) != 0;
        }
        s.Stop();
        Console.WriteLine(s.ElapsedMilliseconds); // *27 ms*        

        Console.ReadLine();
    }
}

在1000万次迭代中,HasFlags扩展方法花费了4793毫秒,而标准的逐位实现只需要27毫秒。

其他回答

c++语法,假设第0位是LSB,假设flags是unsigned long:

检查是否设置:

flags & (1UL << (bit to test# - 1))

检查是否未设置:

invert test !(flag & (...))

Set:

flag |= (1UL << (bit to set# - 1))

明确:

flag &= ~(1UL << (bit to clear# - 1))

切换:

flag ^= (1UL << (bit to set# - 1))

为了测试一点,你可以做以下事情: (假设flags是一个32位的数字)

测试点: if((flags & 0x08) == 0x08)(如果第4位设置为真) 切换回(1 - 0或0 - 1):flags = flags ^ 0x08; 重置位4到零:flags = flags & 0xFFFFFF7F;

@Drew

注意,除了在最简单的情况下,Enum。与手动编写代码相比,HasFlag会带来严重的性能损失。考虑下面的代码:

[Flags]
public enum TestFlags
{
    One = 1,
    Two = 2,
    Three = 4,
    Four = 8,
    Five = 16,
    Six = 32,
    Seven = 64,
    Eight = 128,
    Nine = 256,
    Ten = 512
}


class Program
{
    static void Main(string[] args)
    {
        TestFlags f = TestFlags.Five; /* or any other enum */
        bool result = false;

        Stopwatch s = Stopwatch.StartNew();
        for (int i = 0; i < 10000000; i++)
        {
            result |= f.HasFlag(TestFlags.Three);
        }
        s.Stop();
        Console.WriteLine(s.ElapsedMilliseconds); // *4793 ms*

        s.Restart();
        for (int i = 0; i < 10000000; i++)
        {
            result |= (f & TestFlags.Three) != 0;
        }
        s.Stop();
        Console.WriteLine(s.ElapsedMilliseconds); // *27 ms*        

        Console.ReadLine();
    }
}

在1000万次迭代中,HasFlags扩展方法花费了4793毫秒,而标准的逐位实现只需要27毫秒。

在。net 4中,你现在可以这样写:

flags.HasFlag(FlagsEnum.Bit4)

这是受到在Delphi中使用set作为索引器的启发,在很久以前:

/// Example of using a Boolean indexed property
/// to manipulate a [Flags] enum:

public class BindingFlagsIndexer
{
  BindingFlags flags = BindingFlags.Default;

  public BindingFlagsIndexer()
  {
  }

  public BindingFlagsIndexer( BindingFlags value )
  {
     this.flags = value;
  }

  public bool this[BindingFlags index]
  {
    get
    {
      return (this.flags & index) == index;
    }
    set( bool value )
    {
      if( value )
        this.flags |= index;
      else
        this.flags &= ~index;
    }
  }

  public BindingFlags Value 
  {
    get
    { 
      return flags;
    } 
    set( BindingFlags value ) 
    {
      this.flags = value;
    }
  }

  public static implicit operator BindingFlags( BindingFlagsIndexer src )
  {
     return src != null ? src.Value : BindingFlags.Default;
  }

  public static implicit operator BindingFlagsIndexer( BindingFlags src )
  {
     return new BindingFlagsIndexer( src );
  }

}

public static class Class1
{
  public static void Example()
  {
    BindingFlagsIndexer myFlags = new BindingFlagsIndexer();

    // Sets the flag(s) passed as the indexer:

    myFlags[BindingFlags.ExactBinding] = true;

    // Indexer can specify multiple flags at once:

    myFlags[BindingFlags.Instance | BindingFlags.Static] = true;

    // Get boolean indicating if specified flag(s) are set:

    bool flatten = myFlags[BindingFlags.FlattenHierarchy];

    // use | to test if multiple flags are set:

    bool isProtected = ! myFlags[BindingFlags.Public | BindingFlags.NonPublic];

  }
}