OR列挙型のアイテムを削除する方法は?


181

私は次のような列挙型を持っています:

public enum Blah
{
    RED = 2,
    BLUE = 4,
    GREEN = 8,
    YELLOW = 16
}

Blah colors = Blah.RED | Blah.BLUE | Blah.YELLOW;

可変色から青を削除するにはどうすればよいですか?


2
小さなメモ:C#のビットごとの列挙型は、その上に[フラグ]属性を取得する必要があります。
Nyerguds 2017

@Nyerguds、属性を取得する必要がある理由を説明できますか?
エタン

不明な列挙値を既存の値の組み合わせとして認識するため、デバッグ時にIntelliSenseのサポートが向上します。
Nyerguds 2017年

1
また、より意味のある.ToString()値を提供します。例えば、とRED, BLUE, YELLOWいうより22
シンジャイ2018

回答:


331

「BLUE」の(補数)で&それをする必要があり~ます。

補数演算子は基本的に、指定されたデータ型のすべてのビットを反転または「反転」します。そのため、ある値(その値を 'X'と呼びましょう)および1つ以上のセットビットの補数(これらのビットとその補数を呼びましょう)でAND演算子(&)を使用すると、ステートメントは、from と結果を返します。Q~QX & ~QQX

したがって、BLUEビットを削除またはクリアするには、次のステートメントを使用します。

colorsWithoutBlue = colors & ~Blah.BLUE
colors &= ~Blah.BLUE // This one removes the bit from 'colors' itself

次のように、クリアする複数のビットを指定することもできます。

colorsWithoutBlueOrRed = colors & ~(Blah.BLUE | Blah.RED)
colors &= ~(Blah.BLUE | Blah.RED) // This one removes both bits from 'colors' itself

または代わりに...

colorsWithoutBlueOrRed = colors & ~Blah.BLUE & ~Blah.RED
colors &= ~Blah.BLUE & ~Blah.RED // This one removes both bits from 'colors' itself

要約すると:

  • X | Q ビットを設定します Q
  • X & ~Q ビットをクリアします Q
  • ~X すべてのビットを反転/反転します X

1
したがって、さらに削除したい場合は、次のようにします:&=〜Blah.BLUE&〜Blah.Green?
ブランクマン、2011年

11
ベターはcolors &= ~( Blah.BLUE | Blah.GREEN );
パー

2
なんて珍しい、私はちょうど5日前にもう一度これを行う方法を考えていました:)この質問は私の受信トレイと出来上がりで更新されました!
ブランクマン、2015年

すばらしい答えです。私はあなたがコードサンプルで「&=ではなく「==」ではないことを意味すると思います;)
Dave Jellison

48

他の答えは正しいですが、特に上記から青を削除するには、次のように記述します。

colors &= ~Blah.BLUE;


7

これは、私のようにここでつまずいた他の人々にとって役立つかもしれないと思いました。

値が== 0になるように設定した列挙値の処理方法に注意してください(列挙型の状態が不明またはアイドルになると役立つ場合があります)。これらのビット操作操作に依存すると問題が発生します。

また、他の2の累乗値の組み合わせである列挙値がある場合、たとえば

public enum Colour
{
    None = 0,  // default value
    RED = 2,
    BLUE = 4,
    GREEN = 8,
    YELLOW = 16,
    Orange = 18  // Combined value of RED and YELLOW
}

このような場合、次のような拡張メソッドが役立ちます。

public static Colour UnSet(this Colour states, Colour state)
{
    if ((int)states == 0)
        return states;

    if (states == state)
        return Colour.None;

    return states & ~state;
}

また、結合された値を処理する同等のIsSetメソッド(少しハッキーな方法ですが)

public static bool IsSet(this Colour states, Colour state)
{
    // By default if not OR'd
    if (states == state)
        return true;

    // Combined: One or more bits need to be set
    if( state == Colour.Orange )
        return 0 != (int)(states & state);

    // Non-combined: all bits need to be set
    return (states & state) == state;
}

より簡単な解決策は、フラグとして0を使用しないことです。私は通常、このようなフラグ列挙型を設定します。値を0にして状態を指定するメリットはわかりません。結局のところ、重要なのRed, Blue, Greenは、基になる値ではなく、プログラマーフレンドリーな名前()を使用できるということです。
シンジャイ2018

持つnoneunknown、またはunsetあなたが唯一の赤、青、緑のは、あなたがレッドなどを持ってしようとしているがあれば、いつでも例えば、特定の値がデフォルト設定されていると想定することはできませんとしての値== 0のエントリは、多くの場合、良いことですデフォルト値(たとえば、列挙が作成されたとき、またはユーザーが変更していないときの列挙)
Sverrir Sigmundarson '28

Unset = 1にし1, 2, 4, 8て、値として使用できませんか?デフォルト値が必要な場合、それがデフォルトコンストラクターの目的です。読みやすさを考慮して、できる限り明示的に説明したいと思います。値が指定されていない場合、列挙型をデフォルトのdefault(int)0)に依存することは、おそらく開発者に知られている情報であるにもかかわらず、とにかく卑劣すぎるためです。編集:まあ、Unset = 0にすると何かができなくなりUnset | Blueますか?
シンジャイ2018

編集Sinjaiで正しい軌道に乗っています。未設定の値== 0を維持すると、実際にいくつかの問題が解決します。1つはあなたが言及したものであり、もう1つはすべての列挙値を設定解除した場合であり、それがゼロに設定されている場合、「設定解除」の特別なケースは必要ありません。(たとえば、Red & ~Red最終的にゼロになる場合は、このケースをチェックしてUnset値を明示的に割り当てるコードが必要になります)
Sverrir Sigmundarson

ゴッチャ。未設定のフラグを扱うことがよくありますか?
シンジャイ2018年

2

xor(^)はどうですか?

削除しようとしているFLAGがそこにある場合、それは機能します。そうでない場合は、&を使用する必要があります。

public enum Colour
{
    None = 0,  // default value
    RED = 2,
    BLUE = 4,
    GREEN = 8,
    YELLOW = 16,
    Orange = 18  // Combined value of RED and YELLOW
}

colors = (colors ^ Colour.RED) & colors;

1

フラグの列挙型を単純化し、倍数を避けて読む方がよい場合は、ビットシフトを使用できます。(列挙型フラグに関する大論争を終わらせる良い記事から)

[FLAG]
Enum Blah
{
   RED = 1,
   BLUE = 1 << 1,
   GREEN = 1 << 2,
   YELLOW = 1 << 3
}

また、すべてのビットをクリアする

private static void ClearAllBits()
{
    colors = colors & ~colors;
}

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.