212

私の人生では、ビットフィールドでビットを設定、削除、切り替え、またはテストする方法を思い出せません。これらはめったに必要ないので、よくわからないか、混同しています。したがって、「ビットチートシート」があると便利です。

例えば:

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

また

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

できれば [Flags] 列挙型を使用した C# 構文で、他のすべての一般的な操作の例を挙げていただけますか?

4

11 に答える 11

296

これらの拡張機能についてさらに作業を行いました-コードはこちらにあります

よく使う System.Enum を拡張するいくつかの拡張メソッドを書きました...それらが防弾であると主張しているわけではありませんが、役に立ちました...コメントは削除されました...

namespace Enum.Extensions {

    public static class EnumerationExtensions {

        public static bool Has<T>(this System.Enum type, T value) {
            try {
                return (((int)(object)type & (int)(object)value) == (int)(object)value);
            } 
            catch {
                return false;
            }
        }

        public static bool Is<T>(this System.Enum type, T value) {
            try {
                return (int)(object)type == (int)(object)value;
            }
            catch {
                return false;
            }    
        }


        public static T Add<T>(this System.Enum type, T value) {
            try {
                return (T)(object)(((int)(object)type | (int)(object)value));
            }
            catch(Exception ex) {
                throw new ArgumentException(
                    string.Format(
                        "Could not append value from enumerated type '{0}'.",
                        typeof(T).Name
                        ), ex);
            }    
        }


        public static T Remove<T>(this System.Enum type, T value) {
            try {
                return (T)(object)(((int)(object)type & ~(int)(object)value));
            }
            catch (Exception ex) {
                throw new ArgumentException(
                    string.Format(
                        "Could not remove value from enumerated type '{0}'.",
                        typeof(T).Name
                        ), ex);
            }  
        }

    }
}

次に、それらは次のように使用されます

SomeType value = SomeType.Grapes;
bool isGrapes = value.Is(SomeType.Grapes); //true
bool hasGrapes = value.Has(SomeType.Grapes); //true

value = value.Add(SomeType.Oranges);
value = value.Add(SomeType.Apples);
value = value.Remove(SomeType.Grapes);

bool hasOranges = value.Has(SomeType.Oranges); //true
bool isApples = value.Is(SomeType.Apples); //false
bool hasGrapes = value.Has(SomeType.Grapes); //false
于 2009-01-06T16:31:05.010 に答える
114

.NET 4 では、次のように記述できるようになりました。

flags.HasFlag(FlagsEnum.Bit4)
于 2011-05-30T17:48:11.910 に答える
97

イディオムは、ビットごとの or-equal 演算子を使用してビットを設定することです。

flags |= 0x04;

ビットをクリアするには、イディオムはビットごとに否定を使用することです。

flags &= ~0x04;

場合によっては、ビットを識別するオフセットがあり、イディオムはこれらを左シフトと組み合わせて使用​​することです。

flags |= 1 << offset;
flags &= ~(1 << offset);
于 2008-09-18T15:50:16.257 に答える
22

@ドリュー

最も単純な場合を除いて、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();
    }
}

1,000 万回以上の反復で、HasFlags 拡張メソッドは、標準のビット単位の実装の 27 ミリ秒と比較して、なんと 4793 ミリ秒かかります。

于 2011-08-24T19:51:30.633 に答える
7

ビット 0 が LSB であり、flags が unsigned long であると仮定した場合の C++ 構文:

設定されているかどうかを確認します。

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

設定されていないかどうかを確認します。

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

設定:

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

クリア:

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

トグル:

flag ^= (1UL << (bit to set# - 1))
于 2008-09-18T15:57:25.867 に答える
2

これは、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];

  }
}
于 2012-03-09T22:09:36.517 に答える
2

少しテストするには、次のようにします: (フラグが 32 ビットの数値であると仮定します)

テストビット:

if((flags & 0x08) == 0x08)
(ビット 4 が設定されている場合は true) トグルバック (1 - 0 または 0 - 1):
flags = flags ^ 0x08;
ビット 4 をゼロにリセットします。
flags = flags & 0xFFFFFF7F;

于 2008-09-18T16:00:01.803 に答える
0

C++ 操作は次のとおりです。^ ~ (and、or、xor および非ビット演算)。また、ビットシフト操作である >> と << も興味深いものです。

したがって、ビットがフラグに設定されているかどうかをテストするには、次のようにします。 if (flags & 8) //tests bit 4 has been set

于 2008-09-18T15:50:04.230 に答える