web-dev-qa-db-ja.com

列挙型のアクセス許可に多くの場合、0、1、2、4の値があるのはなぜですか?

なぜ人々は常に0, 1, 2, 4, 8ではなく0, 1, 2, 3, 4のような列挙値を使用するのですか?

これはビット演算などと関係がありますか?

私はこれがどのように正しく使用されるかについての小さなサンプルスニペットを本当に感謝します:)

[Flags]
public enum Permissions
{
    None   = 0,
    Read   = 1,
    Write  = 2,
    Delete = 4
}
157
Pascal

それらは2のべき乗であり、私はこれを行うことができるからです。

var permissions = Permissions.Read | Permissions.Write;

そしておそらく後で...

if( (permissions & Permissions.Write) == Permissions.Write )
{
    // we have write access
}

これはビットフィールドであり、各セットビットは許可(または列挙値が論理的に対応するもの)に対応します。これらが1, 2, 3, ...として定義されている場合、この方法でビットごとの演算子を使用して意味のある結果を取得することはできません。深く掘り下げるには...

Permissions.Read   == 1 == 00000001
Permissions.Write  == 2 == 00000010
Permissions.Delete == 4 == 00000100

ここにパターンがありますか?私の元の例、つまり

var permissions = Permissions.Read | Permissions.Write;

その後...

permissions == 00000011

見る? ReadビットとWriteビットの両方が設定されており、それを個別に確認できます(Deleteビットがnotであるため、これが設定されているため、値は削除の許可を伝えません)。

単一のビットフィールドに複数のフラグを格納できます。

265
Ed S.

それでも他の回答から明らかでない場合は、次のように考えてください。

[Flags] 
public enum Permissions 
{   
   None = 0,   
   Read = 1,     
   Write = 2,   
   Delete = 4 
} 

書くための短い方法です:

public enum Permissions 
{   
    DeleteNoWriteNoReadNo = 0,   // None
    DeleteNoWriteNoReadYes = 1,  // Read
    DeleteNoWriteYesReadNo = 2,  // Write
    DeleteNoWriteYesReadYes = 3, // Read + Write
    DeleteYesWriteNoReadNo = 4,   // Delete
    DeleteYesWriteNoReadYes = 5,  // Read + Delete
    DeleteYesWriteYesReadNo = 6,  // Write + Delete
    DeleteYesWriteYesReadYes = 7, // Read + Write + Delete
} 

8つの可能性がありますが、それらを4つのメンバーのみの組み合わせとして表すことができます。 16の可能性がある場合、それらを5つのメンバーのみの組み合わせとして表すことができます。 40億の可能性がある場合、それらを33のメンバーの組み合わせとして表すことができます!列挙で40億個のアイテムに名前を付けようとするよりも、33個のメンバー(それぞれゼロ(ゼロを除く)の2のべき乗)のみを使用する方が明らかにはるかに優れています。

144
Eric Lippert

これらの値はバイナリで一意のビット位置を表すため:

1 == binary 00000001
2 == binary 00000010
4 == binary 00000100

など

1 | 2 == binary 00000011

編集:

3 == binary 00000011

2進数の3は、1の場所と2の場所の両方で1の値で表されます。実際には、値1 | 2と同じです。したがって、バイナリの場所をフラグとして使用して何らかの状態を表す場合、3は通常意味がありません(実際には2つの組み合わせである論理値がない限り)

さらに明確にするために、次のように列挙型の例を拡張できます。

[Flags]
public Enum Permissions
{
  None = 0,   // Binary 0000000
  Read = 1,   // Binary 0000001
  Write = 2,  // Binary 0000010
  Delete = 4, // Binary 0000100
  All = 7,    // Binary 0000111
}

したがって、私はPermissions.Allを持っていますが、Permissions.ReadPermissions.Write、およびPermissions.Deleteも暗黙的に持っています

36
Chris Shain
[Flags]
public Enum Permissions
{
    None   =    0; //0000000
    Read   =    1; //0000001
    Write  = 1<<1; //0000010
    Delete = 1<<2; //0000100
    Blah1  = 1<<3; //0001000
    Blah2  = 1<<4; //0010000
}

このように書く方が理解しやすく、読みやすく、計算する必要はないと思います。

9
Dozer

これらは、列挙値の組み合わせを許可するビットフラグを表すために使用されます。 16進表記で値を記述するとより明確になると思います

[Flags]
public Enum Permissions
{
  None =  0x00,
  Read =  0x01,
  Write = 0x02,
  Delete= 0x04,
  Blah1 = 0x08,
  Blah2 = 0x10
}
5
JaredPar

これは本当にコメントですが、書式設定をサポートしていないため、フラグ列挙の設定に使用したメソッドを含めたいだけです。

[Flags]
public enum FlagTest
{
    None = 0,
    Read = 1,
    Write = Read * 2,
    Delete = Write * 2,
    ReadWrite = Read|Write
}

このアプローチは、フラグをアルファベット順に維持したい場合に開発中に特に役立ちます。新しいフラグ値を追加する必要があると判断した場合は、アルファベット順にそれを挿入するだけで、変更する必要がある値はその前にある値のみです。

ただし、ソリューションが実稼働システムに公開されると(特に、Webサービスなどで密結合なしで列挙が公開される場合)、列挙内の既存の値を変更しないことを強くお勧めします。

1
Mike Guthrie

これに対する多くの良い答えがあります…私はただ..あなたが気に入らない場合、または簡単に把握できない what the <<構文は表現しようとしています。私は個人的に代替手段を好みます(そして、あえて言うと、straightforward enum宣言スタイル)…

typedef NS_OPTIONS(NSUInteger, Align) {
    AlignLeft         = 00000001,
    AlignRight        = 00000010,
    AlignTop          = 00000100,
    AlignBottom       = 00001000,
    AlignTopLeft      = 00000101,
    AlignTopRight     = 00000110,
    AlignBottomLeft   = 00001001,
    AlignBottomRight  = 00001010
};

NSLog(@"%ld == %ld", AlignLeft | AlignBottom, AlignBottomLeft);

LOG 513 == 513

理解するのが非常に簡単です(少なくとも、私にとっては)。必要な結果を記述し、希望する結果を取得します。「計算」は必要ありません。

1
Alex Gray